[
  {
    "path": ".editorconfig",
    "content": "# http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespace = true\nmax_line_length = 100\n\n[*.{ts, tsx}]\nij_typescript_enforce_trailing_comma = keep\nij_typescript_use_double_quotes = false\nij_typescript_force_quote_style = true\nij_typescript_align_imports = false\nij_typescript_align_multiline_ternary_operation = false\nij_typescript_align_multiline_parameters_in_calls = false\nij_typescript_align_multiline_parameters = false\nij_typescript_align_multiline_chained_methods = false\nij_typescript_else_on_new_line = false\nij_typescript_catch_on_new_line = false\nij_typescript_spaces_within_interpolation_expressions = false\n\n[*.md]\nmax_line_length = 100\ntrim_trailing_whitespace = false\n\n[COMMIT_EDITMSG]\nmax_line_length = 80\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  extends: ['react-app', 'prettier'],\n  plugins: ['prettier'],\n  rules: {\n    'prettier/prettier': [\n      'error',\n      {\n        singleQuote: true,\n        trailingComma: 'es5',\n        tabWidth: 2,\n        printWidth: 100,\n        semicolons: true,\n        quoteProps: 'as-needed',\n        jsxSingleQuote: false,\n        bracketSpacing: true,\n        jsxBracketSameLine: true,\n        arrowParens: 'always',\n        endOfLine: 'lf',\n      },\n    ],\n  },\n};\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [\n  \"streamich\",\n  \"wardoost\",\n  \"xobotyi\",\n  \"Belco90\",\n  \"ankithkonda\",\n  \"ayush987goyal\",\n  \"NullVoxPopuli\",\n  \"lintuming\",\n  \"Granipouss\",\n  \"ythecombinator\",\n  \"james2406\",\n  \"jakapatb\",\n  \"MrHuangJser\",\n  \"zaguiini\",\n  \"ppeeou\",\n  \"liuyuchenzh\",\n  \"brickspert\",\n  \"artywhite\",\n  \"PetterIve\",\n  \"realdennis\",\n  \"lvl99\",\n  \"gelove\",\n  \"KusStar\",\n  \"xiaoxiangmoe\",\n  \"nmccready\",\n  \"mattleonowicz\",\n  \"kevinnorris\",\n  \"dubzzz\",\n  \"dependabot[bot]\",\n  \"ShizukuIchi\",\n  \"ManojBahuguna\",\n  \"Jivings\",\n  \"Dosant\",\n  \"zsh2401\",\n  \"xiaoboost\",\n  \"revskill10\",\n  \"mtinner\",\n  \"monkeywithacupcake\",\n  \"mitchheddles\",\n  \"maxzitron\",\n  \"macinjoke\",\n  \"jeetiss\",\n  \"ilyalesik\",\n  \"hijiangtao\",\n  \"f\",\n  \"elliottsj\",\n  \"droganov\",\n  \"denysdovhan\",\n  \"dabuside\",\n  \"benneq\",\n  \"azukaar\",\n  \"ariesjia\",\n  \"andrico1234\",\n  \"adesurirey\",\n  \"OBe95\",\n  \"FredyC\",\n  \"Cretezy\",\n  \"zyy7259\",\n  \"zslabs\",\n  \"vinitsood\",\n  \"uxitten\",\n  \"thevtm\",\n  \"tanem\",\n  \"suyingtao\",\n  \"srph\",\n  \"rkostrzewski\",\n  \"qianL93\",\n  \"o-alexandrov\",\n  \"nucleartux\",\n  \"natew\",\n  \"maxmalov\",\n  \"liaoyinglong\",\n  \"koenvanzuijlen\",\n  \"josmardias\",\n  \"jeemyeong\",\n  \"jazzqi\",\n  \"jakyle\",\n  \"jakeboone02\",\n  \"inker\",\n  \"glarivie\",\n  \"garrettmaring\",\n  \"dovidweisz\",\n  \"daniel-hauser\",\n  \"d-asensio\",\n  \"charlax\",\n  \"TylerR909\",\n  \"Rogdham\",\n  \"OctoD\",\n  \"MajorBreakfast\",\n  \"Jfelix61\",\n  \"Flydiverny\",\n  \"FlickerLogicalStack\",\n  \"DmacMcgreg\",\n  \"Dattaya\",\n  \"Andrey-Bazhanov\",\n  \"AlvaroBernalG\"\n]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report if you having any problems using the package\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**What is the current behavior?**\n\n**Steps to reproduce it and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have extra dependencies other than `react-use`. Paste the link to your [JSFiddle](https://jsfiddle.net) or [CodeSandbox](https://codesandbox.io) example below:**\n\n**What is the expected behavior?**\n\n**A little about versions:**  \n- _OS_: \n- _Browser (vendor and version)_: \n- _React_: \n- _`react-use`_: \n- _Did this worked in the previous package version?_\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Have an idea? Great! Let us know, maybe we`ve been waiting only for you =)\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"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "# Description\n\n<!-- Please include a summary of the change along with relevant motivation and context. -->\n\n\n## Type of change\n\n<!-- Check all relevant options. -->\n- [ ] Bug fix _(non-breaking change which fixes an issue)_\n- [ ] New feature _(non-breaking change which adds functionality)_\n- [ ] **Breaking change** _(fix or feature that would cause existing functionality to not work as before)_\n\n# Checklist\n- [ ] Read the [Contributing Guide](https://github.com/streamich/react-use/blob/master/CONTRIBUTING.md)\n- [ ] Perform a code self-review\n- [ ] Comment the code, particularly in hard-to-understand areas\n- [ ] Add documentation\n- [ ] Add hook's story at Storybook\n- [ ] Cover changes with tests\n- [ ] Ensure the test suite passes (`yarn test`)\n- [ ] Provide 100% tests coverage\n- [ ] Make sure code lints (`yarn lint`). Fix it with `yarn lint:fix` in case of failure.\n- [ ] Make sure types are fine (`yarn lint:types`).\n\n<!-- If you can't check all the checkboxes right now - check what you can, create a Draft PR, make some changes if needed and get back to it when you will be able to put some marks in list. -->\n"
  },
  {
    "path": ".github/workflows/check-codebase.yml",
    "content": "name: Check codebase\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@v2\n\n      - name: Setup node\n        uses: actions/setup-node@v1\n        with:\n          node-version: 20\n\n      - name: Install dependencies\n        run: yarn install --frozen-lockfile\n\n      - name: Run build\n        run: yarn build\n\n  # storybook:\n  #   name: Storybook\n  #   runs-on: ubuntu-latest\n  #   steps:\n  #     - name: Check out repository\n  #       uses: actions/checkout@v2\n\n  #     - name: Setup node\n  #       uses: actions/setup-node@v1\n  #       with:\n  #         node-version: 20\n\n  #     - name: Install dependencies\n  #       run: yarn install --frozen-lockfile\n\n  #     - name: Run build:storybook\n  #       run: yarn storybook:build\n\n  lint:\n    name: Linting\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@v2\n\n      - name: Setup node\n        uses: actions/setup-node@v1\n        with:\n          node-version: 20\n\n      - name: Install dependencies\n        run: yarn install --frozen-lockfile\n\n      - name: Lint with ESLint\n        run: yarn lint\n\n      - name: Lint with TSC\n        if: ${{ always() }}\n        run: yarn lint:types\n\n  unit-tests:\n    name: Unit tests\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [macos-latest, ubuntu-latest]\n        node: [20, 22]\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@v2\n\n      - name: Setup node\n        uses: actions/setup-node@v1\n        with:\n          node-version: ${{ matrix.node }}\n\n      - name: Install dependencies\n        run: yarn install --frozen-lockfile\n\n      - name: Run unit tests\n        run: yarn test\n"
  },
  {
    "path": ".github/workflows/mirror.yml",
    "content": "name: Node.js CI\n\non:\n  push:\n    branches: [master]\n\njobs:\n  mirror:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - name: Push To Gitlab\n        env:\n          token: ${{ secrets.GITLAB_TOKEN }}\n        run: |\n          git config user.name \"streamich\"\n          git config user.email \"react-use+streamich@users.noreply.github.com\"\n          git remote add mirror \"https://oauth2:${token}@gitlab.com/streamich/react-use.git\"\n          git push mirror master\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Node.js CI\n\non:\n  push:\n    branches: [master, next]\n\njobs:\n  release:\n    if: ${{ github.event_name == 'push' && (github.event.ref == 'refs/heads/master' || github.event.ref == 'refs/heads/next') }}\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-version: [22.x]\n    steps:\n      - uses: actions/checkout@v4\n      - name: Use Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: yarn\n      - run: yarn install --frozen-lockfile\n      - run: yarn lint\n      - run: yarn test\n      - run: yarn lint:types\n      - run: yarn build\n      - name: Semantic Release\n        uses: cycjimmy/semantic-release-action@v4\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# IDE files\n.idea\n.vscode\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# build output\nlib/\nesm\n\n.DS_Store\n\nsrc/parser.ts\n\n.cache/\n.puppet-master/\n\nstorybook-static/\npackage-lock.json\n"
  },
  {
    "path": ".storybook/addons.js",
    "content": "import '@storybook/addon-knobs/register';\nimport '@storybook/addon-options/register';\nimport '@storybook/addon-actions/register';\nimport '@storybook/addon-notes/register';\n"
  },
  {
    "path": ".storybook/config.js",
    "content": "import {configure} from '@storybook/react';\nimport {setOptions} from '@storybook/addon-options';\n\nsetOptions({\n  sortStoriesByKind: false,\n  showStoriesPanel: true,\n  showAddonPanel: true,\n  showSearchBox: false,\n  addonPanelInRight: true,\n  hierarchySeparator: /\\//,\n  hierarchyRootSeparator: /\\|/,\n  sidebarAnimations: false,\n});\n\nconst req = require.context('../stories/', true, /\\.story\\.tsx?$/);\n\nconst loadStories = () => {\n  req.keys().forEach((filename) => req(filename));\n};\n\nconfigure(loadStories, module);\n"
  },
  {
    "path": ".storybook/webpack.config.js",
    "content": "const path = require('path');\nconst { compilerOptions } = require('../tsconfig.json');\nconst ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');\n\nconst basedir = path.join(__dirname, '..');\n\nmodule.exports = async ({ config, mode }) => {\n  config.module.rules.push(\n    {\n      test: /\\.md?$/,\n      loader: \"markdown-loader\",\n    },\n    {\n      test: /\\.tsx?$/,\n      loader: 'ts-loader',\n      include: [\n        path.join(basedir, 'src'),\n        path.join(basedir, 'stories'),\n      ],\n      options: {\n        transpileOnly: true, // use transpileOnly mode to speed-up compilation\n        compilerOptions: {\n          ...compilerOptions,\n          declaration: false,\n        },\n      },\n    },\n  );\n\n  config.plugins.push(new ForkTsCheckerWebpackPlugin());\n\n  config.resolve.extensions = ['.ts', '.tsx', '.js', '.jsx'];\n  config.resolve.enforceExtension = false;\n\n  // disable the hint about too big bundle\n  config.performance.hints = false;\n\n  return config;\n};\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nos:\n  - linux\ncache:\n  yarn: true\n  directories:\n    - ~/.npm\nnotifications:\n  email: false\nnode_js:\n  - '10'\nscript:\n  - yarn lint\n  - yarn test\n  - yarn build\n  - yarn storybook:build\nmatrix:\n  allow_failures: []\n  fast_finish: true\nbranches:\n  except:\n    - /^v\\d+\\.\\d+\\.\\d+$/\n    - master\n    - next\n    - gh-pages\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# [17.6.0](https://github.com/streamich/react-use/compare/v17.5.1...v17.6.0) (2024-12-09)\n\n\n### Features\n\n* add onChange callback to useWindowSize ([ea656f7](https://github.com/streamich/react-use/commit/ea656f7e751b8366360ce2aa8238057bbbc1251a))\n* add onChange callback to useWindowSize ([3eb531a](https://github.com/streamich/react-use/commit/3eb531ac9e9e04641df29aafbd2677869cdcb085))\n\n## [17.5.1](https://github.com/streamich/react-use/compare/v17.5.0...v17.5.1) (2024-07-20)\n\n\n### Bug Fixes\n\n* 🐛 bump nano-css dependency ([adfb337](https://github.com/streamich/react-use/commit/adfb337d5b11427798afc5a21c6ebdaa76212182))\n\n# [17.5.0](https://github.com/streamich/react-use/compare/v17.4.4...v17.5.0) (2024-01-22)\n\n\n### Features\n\n* add `isFirst` and `isLast` methods to `useStateList` hook ([ac64414](https://github.com/streamich/react-use/commit/ac64414bea4c8afadfb382da9fea44ee89b41e2d))\n* **pencil:** add isFirst and isLast return value to 'useStateList' ([75218e4](https://github.com/streamich/react-use/commit/75218e45dfdcdc6ea193e278cb97ceee98c00f1b))\n* **pencil:** fix with yarn lint:fix ([6a9dde5](https://github.com/streamich/react-use/commit/6a9dde596ae25c0dd2fa97b0cf354143fbc5b5ff))\n\n## [17.4.4](https://github.com/streamich/react-use/compare/v17.4.3...v17.4.4) (2024-01-21)\n\n\n### Bug Fixes\n\n* typo in example ([0534648](https://github.com/streamich/react-use/commit/05346481a15a321b13838eead0bda3024b0d163f))\n\n## [17.4.3](https://github.com/streamich/react-use/compare/v17.4.2...v17.4.3) (2024-01-13)\n\n\n### Bug Fixes\n\n* update useMedia hook to use recommended approach of MDN ([e7379f0](https://github.com/streamich/react-use/commit/e7379f088787cbf9274c1fc21d36061f04855e4c))\n\n## [17.4.2](https://github.com/streamich/react-use/compare/v17.4.1...v17.4.2) (2023-12-01)\n\n\n### Bug Fixes\n\n* correct peer dependencies ([d770587](https://github.com/streamich/react-use/commit/d77058729654397b68b251e8211bf0edc0b4ed50))\n\n## [17.4.1](https://github.com/streamich/react-use/compare/v17.4.0...v17.4.1) (2023-11-28)\n\n\n### Bug Fixes\n\n* 🐛 bump nano-css version ([812952b](https://github.com/streamich/react-use/commit/812952bb9ff004a844ec4285ad6c65d39597b11c))\n\n# [17.4.0](https://github.com/streamich/react-use/compare/v17.3.3...v17.4.0) (2022-05-20)\n\n\n### Features\n\n* add usePinchZoom sensor hook ([3e042cb](https://github.com/streamich/react-use/commit/3e042cb2f3022349a53199b5cc5c380e3ebd9975))\n\n## [17.3.3](https://github.com/streamich/react-use/compare/v17.3.2...v17.3.3) (2022-05-20)\n\n\n### Bug Fixes\n\n* bump React peer dependency version ([532e865](https://github.com/streamich/react-use/commit/532e8653a50d39dd439d9664d4813a1d7a5b4f3c))\n* resolve [#2319](https://github.com/streamich/react-use/issues/2319) ([4884b2c](https://github.com/streamich/react-use/commit/4884b2c74085e0841af7c36cca34e16d698d1b4c))\n* resolve @types/react@18 break change, React.FC ([20b7817](https://github.com/streamich/react-use/commit/20b78178d0033cc2e0c2a904e413b20ee864c816))\n\n## [17.3.2](https://github.com/streamich/react-use/compare/v17.3.1...v17.3.2) (2021-12-30)\n\n\n### Bug Fixes\n\n* useMedia SSR hydration bug with defaultState ([#2216](https://github.com/streamich/react-use/issues/2216)) ([5c01189](https://github.com/streamich/react-use/commit/5c0118941280bb265ca7813afb987f89c8c97a17))\n\n## [17.3.1](https://github.com/streamich/react-use/compare/v17.3.0...v17.3.1) (2021-08-31)\n\n\n### Performance Improvements\n\n* ⚡️ change title only if it changed ([51ef8d9](https://github.com/streamich/react-use/commit/51ef8d99bad31186ec5420d8b729748507c8a1bf))\n\n# [17.3.0](https://github.com/streamich/react-use/compare/v17.2.4...v17.3.0) (2021-08-31)\n\n\n### Bug Fixes\n\n* do not re-render unncessarily in useAsyncFn hook ([fa3ba25](https://github.com/streamich/react-use/commit/fa3ba2520ede6866b599f6df55fdfa6395058cd2))\n\n\n### Features\n\n* useAudio add playing state ([3203610](https://github.com/streamich/react-use/commit/3203610efdcb8e1fe3c6a17ea19e41bacbeb851b))\n\n## [17.2.4](https://github.com/streamich/react-use/compare/v17.2.3...v17.2.4) (2021-04-23)\n\n\n### Bug Fixes\n\n* lint issues. ([66b0f23](https://github.com/streamich/react-use/commit/66b0f235477c5f93807df75a53a84b3c5cd053e5))\n* **useLocalStorage:** reinitialize on key change ([fdd1b23](https://github.com/streamich/react-use/commit/fdd1b23fd7ba6ae30139eeef02c552a8c7d6d333))\n* add generic typing to createHTMLMediaHook. no typecheck problem with ref anymore. ([1f547ef](https://github.com/streamich/react-use/commit/1f547efb12d6cbe7687e86925ad80bd85fac3dfd))\n* add generic typing to createHTMLMediaHook. no typecheck problem with ref anymore. ([ac4dd78](https://github.com/streamich/react-use/commit/ac4dd786f42a2c59bdaaf9ddebe2e830982d7fcc))\n\n## [17.2.3](https://github.com/streamich/react-use/compare/v17.2.2...v17.2.3) (2021-04-06)\n\n\n### Bug Fixes\n\n* lint issues. ([5a5a575](https://github.com/streamich/react-use/commit/5a5a5755bc1f10add9c7a100ea6577ab6d427c0c))\n\n## [17.2.2](https://github.com/streamich/react-use/compare/v17.2.1...v17.2.2) (2021-04-06)\n\n\n### Bug Fixes\n\n* **useStateWithHistory:** support callback style setState ([fca687d](https://github.com/streamich/react-use/commit/fca687d32c37148dab3072f053109f6c4d3c36ba))\n\n## [17.2.1](https://github.com/streamich/react-use/compare/v17.2.0...v17.2.1) (2021-03-11)\n\n\n### Bug Fixes\n\n* lint issues. ([3e8af15](https://github.com/streamich/react-use/commit/3e8af15086135c873d18079a0b92b21da668a2ff))\n* useMeasure type definitions for SVG ([e200f7f](https://github.com/streamich/react-use/commit/e200f7fcbb371a1d794be8d350f9559f940e5760))\n* useUnmountPromise stops on immediate update ([9ff5c09](https://github.com/streamich/react-use/commit/9ff5c09e671c4f07f25f30a60617fca7660e7607))\n\n# [17.2.0](https://github.com/streamich/react-use/compare/v17.1.1...v17.2.0) (2021-03-10)\n\n\n### Bug Fixes\n\n* delete isClient ([72f4cb9](https://github.com/streamich/react-use/commit/72f4cb9b405b3729975bca3acb06658ca467d15b))\n* lint issues. ([dc5bbe0](https://github.com/streamich/react-use/commit/dc5bbe0e94d131dda90942ba90c14b200df3f34e))\n* **useOrientation:** handle orientation being 0 ([793b053](https://github.com/streamich/react-use/commit/793b0539f0305e2512e7022c45a5c33b842d24d5))\n* **useOrientation:** update tests to increase coverage ([f9c743f](https://github.com/streamich/react-use/commit/f9c743fa8375ef726d33f85285d4a5af608f9a42))\n* use window inside useEffect ([2f33aa8](https://github.com/streamich/react-use/commit/2f33aa8182c92bf56d49ec3184e6b20f0c0c1e1e))\n\n\n### Features\n\n* **useOrientation:** add tests ([f45cb70](https://github.com/streamich/react-use/commit/f45cb707b52363f1cb1b32a0ebf2fdbdae79b322))\n\n## [17.1.1](https://github.com/streamich/react-use/compare/v17.1.0...v17.1.1) (2021-02-10)\n\n\n### Bug Fixes\n\n* useMountedState should not change state on componentDidUpdate lifecycle ([701b306](https://github.com/streamich/react-use/commit/701b306ed97382cbec73c834f6d3dd7baa58e339))\n\n# [17.1.0](https://github.com/streamich/react-use/compare/v17.0.2...v17.1.0) (2021-02-01)\n\n\n### Features\n\n* **prettier:** make prettier a part of eslint. ([b6993a6](https://github.com/streamich/react-use/commit/b6993a6f95a1b493945c03aecc44dafd10870816))\n\n## [17.0.2](https://github.com/streamich/react-use/compare/v17.0.1...v17.0.2) (2021-02-01)\n\n\n### Bug Fixes\n\n* proper definition for `useMeasure` ([1461527](https://github.com/streamich/react-use/commit/1461527ffc55b2a1e3c9dc6a0efc2572b66e5381))\n\n## [17.0.1](https://github.com/streamich/react-use/compare/v17.0.0...v17.0.1) (2021-01-31)\n\n\n### Bug Fixes\n\n* proper definition for isBrowser and isNavigator states. ([a087deb](https://github.com/streamich/react-use/commit/a087deb48e57b1f0a23a2d0a28d0c2d10a640cd6)), closes [#1777](https://github.com/streamich/react-use/issues/1777)\n\n# [17.0.0](https://github.com/streamich/react-use/compare/v16.1.0...v17.0.0) (2021-01-31)\n\n\n### Features\n\n* refactor the useNetwork hook. ([23037f2](https://github.com/streamich/react-use/commit/23037f207d07604dd2cd7e2cc4ba9475221be780))\n\n\n### BREAKING CHANGES\n\n* `useNetwork` hook renamed to `useNetworkState`.\n\n# [16.1.0](https://github.com/streamich/react-use/compare/v16.0.0...v16.1.0) (2021-01-31)\n\n\n### Features\n\n* improve `on` and `off` util functions typing. ([723c588](https://github.com/streamich/react-use/commit/723c588fef6aba9f10ea9f5ea7bc444532519f9a))\n\n# [16.0.0](https://github.com/streamich/react-use/compare/v15.3.8...v16.0.0) (2021-01-30)\n\n\n### chore\n\n* refactoring and rearrangement. ([a27f09f](https://github.com/streamich/react-use/commit/a27f09fd367f8b172866b5fcbaf66f9a5a3481bb))\n\n\n### BREAKING CHANGES\n\n* all `create*` factories been moved to `factory` subdirectory and in case direct import should be imported like `react-use/esm/factory/createBreakpoint`\n* `comps` directory renamed to `component`\n\n## [15.3.8](https://github.com/streamich/react-use/compare/v15.3.7...v15.3.8) (2021-01-08)\n\n\n### Bug Fixes\n\n* improve useStateValidator and useMultiStateValidator typings. ([acff81d](https://github.com/streamich/react-use/commit/acff81d99abdbbefcc2985297ee01c3cda9ef4c9))\n\n## [15.3.7](https://github.com/streamich/react-use/compare/v15.3.6...v15.3.7) (2021-01-08)\n\n\n### Bug Fixes\n\n* [#1646](https://github.com/streamich/react-use/issues/1646) ([ebc7094](https://github.com/streamich/react-use/commit/ebc7094bbc156be57b3de855c6984c1d056cf0e6))\n\n## [15.3.6](https://github.com/streamich/react-use/compare/v15.3.5...v15.3.6) (2021-01-07)\n\n\n### Bug Fixes\n\n* Fix issues in tests ([7668ce5](https://github.com/streamich/react-use/commit/7668ce5c5f0f186437907f1c352d3a62e3ae8ba7))\n\n## [15.3.4](https://github.com/streamich/react-use/compare/v15.3.3...v15.3.4) (2020-09-04)\n\n\n### Bug Fixes\n\n* useLongPress hook linting fixes. ([479dd99](https://github.com/streamich/react-use/commit/479dd9977bfcc43ccadc58eb93690adee462a16e))\n\n## [15.3.3](https://github.com/streamich/react-use/compare/v15.3.2...v15.3.3) (2020-07-24)\n\n\n### Bug Fixes\n\n* replace createFactory usages with createElement ([ad29bea](https://github.com/streamich/react-use/commit/ad29bea7b03f46aa697e6623bdf7a17347ace651))\n\n## [15.3.2](https://github.com/streamich/react-use/compare/v15.3.1...v15.3.2) (2020-06-29)\n\n\n### Bug Fixes\n\n* **useFullscreen:** fix typings so [#1205](https://github.com/streamich/react-use/issues/1205) can be merged. ([e6e55a3](https://github.com/streamich/react-use/commit/e6e55a3f94993b621566ac66488fd973e992704f))\n\n## [15.3.1](https://github.com/streamich/react-use/compare/v15.3.0...v15.3.1) (2020-06-29)\n\n\n### Bug Fixes\n\n* **usePrevious:** revert the reworked variant as a fix of [#1315](https://github.com/streamich/react-use/issues/1315) ([a4279eb](https://github.com/streamich/react-use/commit/a4279eb660f6b433ed88e0d90c2bb0b3158d3b00))\n\n# [15.3.0](https://github.com/streamich/react-use/compare/v15.2.5...v15.3.0) (2020-06-19)\n\n\n### Features\n\n* **usePrevious:** reworked the hook, now it is more memory-efficient. ([8c6f467](https://github.com/streamich/react-use/commit/8c6f4675beac9c71e96126dd6f06f455c4e4bf01))\n\n## [15.2.5](https://github.com/streamich/react-use/compare/v15.2.4...v15.2.5) (2020-06-15)\n\n\n### Bug Fixes\n\n* bump react-universal-interface ([1540c1a](https://github.com/streamich/react-use/commit/1540c1ab8f338dfa2f53de16506fbf47803d45ba))\n\n## [15.2.4](https://github.com/streamich/react-use/compare/v15.2.3...v15.2.4) (2020-06-13)\n\n\n### Bug Fixes\n\n*  doesn't unlock the body on unmount ([1ead4ef](https://github.com/streamich/react-use/commit/1ead4efab6c67131e480570b578b0ce803204953))\n\n## [15.2.3](https://github.com/streamich/react-use/compare/v15.2.2...v15.2.3) (2020-06-13)\n\n\n### Bug Fixes\n\n* 🐛 improve how text is dropped in useDrop hook ([b2f46d1](https://github.com/streamich/react-use/commit/b2f46d10f25c5e658bb7f790950a1fd9a4e5e288))\n\n## [15.2.2](https://github.com/streamich/react-use/compare/v15.2.1...v15.2.2) (2020-06-08)\n\n\n### Bug Fixes\n\n* repair useKeyboardJs hook ([8410bb0](https://github.com/streamich/react-use/commit/8410bb042fec8f1996e8bcecb85fadfbb414b3f9))\n\n## [15.2.1](https://github.com/streamich/react-use/compare/v15.2.0...v15.2.1) (2020-06-08)\n\n\n### Bug Fixes\n\n* 🐛 bump fast-deep-equal, and consume it through ES import ([f3c715c](https://github.com/streamich/react-use/commit/f3c715c12412224be815e0d1bc3e2285f275df26))\n\n# [15.2.0](https://github.com/streamich/react-use/compare/v15.1.1...v15.2.0) (2020-06-07)\n\n\n### Features\n\n* add useMouseWheel hook ([d714b12](https://github.com/streamich/react-use/commit/d714b12e8b2d071c65fe4dc7643be10f69dc5dba))\n\n## [15.1.1](https://github.com/streamich/react-use/compare/v15.1.0...v15.1.1) (2020-05-30)\n\n\n### Bug Fixes\n\n* 🐛 use useIsomorphicLayoutEffect everywhere ([dad26e5](https://github.com/streamich/react-use/commit/dad26e507d3409300f945bc57930f88c5a11953d))\n\n# [15.1.0](https://github.com/streamich/react-use/compare/v15.0.3...v15.1.0) (2020-05-18)\n\n\n### Bug Fixes\n\n* display alert timeout in story ([2bb65ef](https://github.com/streamich/react-use/commit/2bb65ef3d85e82b6bd134a714e51e27876037734))\n* mutate ref in render directly ([5488f5e](https://github.com/streamich/react-use/commit/5488f5eb3e8504dcae03584b5797a48659e16623))\n\n\n### Features\n\n* add useLatest hook ([d6fe267](https://github.com/streamich/react-use/commit/d6fe2676153f19302ce170b03ceadc3bab5a945a))\n\n## [15.0.3](https://github.com/streamich/react-use/compare/v15.0.2...v15.0.3) (2020-05-18)\n\n\n### Bug Fixes\n\n* 🐛 correct useMeasure typings ([bedbad7](https://github.com/streamich/react-use/commit/bedbad723171ed1946bc80f72609432983d4c1ba))\n\n## [15.0.2](https://github.com/streamich/react-use/compare/v15.0.1...v15.0.2) (2020-05-17)\n\n\n### Bug Fixes\n\n* 🐛 dont memoize useScratch event handlers ([ffc7579](https://github.com/streamich/react-use/commit/ffc75790e329cb26000a174074c07d80283b5443))\n\n## [15.0.1](https://github.com/streamich/react-use/compare/v15.0.0...v15.0.1) (2020-05-16)\n\n\n### Bug Fixes\n\n* **deps:** update dependency tslib to v2 ([6aebf3c](https://github.com/streamich/react-use/commit/6aebf3c25e14d12d8f34e62ecbaecfd3125cf2d9))\n\n# [15.0.0](https://github.com/streamich/react-use/compare/v14.3.0...v15.0.0) (2020-05-16)\n\n\n* v15 release ([0f82ba6](https://github.com/streamich/react-use/commit/0f82ba650ed3e8b05b5458a243e7eb246fd954d2))\n\n\n### Bug Fixes\n\n* 🐛 better serialization handling in useLocalStorage hook ([68fb835](https://github.com/streamich/react-use/commit/68fb835ea64cf5587c99645a09c6de93ab1b71df))\n* 🐛 correctly test if env is browser in useMeasure ([9ae494f](https://github.com/streamich/react-use/commit/9ae494fc1874619aad2f3856df790cbc1a2a8239))\n* 🐛 make useMeasure work on server ([2daf769](https://github.com/streamich/react-use/commit/2daf76990d0e1040f8c0f31e16e7c1eebd94c9bf))\n* 🐛 remove set dependencies in useSet hook ([90ba9d0](https://github.com/streamich/react-use/commit/90ba9d000ff35039028cb66753114a6b0b452491))\n* 🐛 revert useMeasure defaults to zeros ([dc92b64](https://github.com/streamich/react-use/commit/dc92b646d0cd0f12868fde370c83e94ca3c7e297))\n* remove console log 🤓 ([f17c8a0](https://github.com/streamich/react-use/commit/f17c8a0f8e63bfddb8f13a094edbea1e3ee9680b))\n* **useLocalStorage:** using undefined for empty value instead of null ([1620e01](https://github.com/streamich/react-use/commit/1620e019fff94fb4a7a711fd3121ec02c7e99301))\n* use latest set object in useSet \"has\" method ([41f9452](https://github.com/streamich/react-use/commit/41f9452722d6fb7d2628480d7ce657e4f08e441a))\n\n\n### Features\n\n* 🎸 add useScratch() sensor hook ([58db2f9](https://github.com/streamich/react-use/commit/58db2f989d5d4f75ac5e8ef54c25a9df8bb173a5))\n* 🎸 catch up with v14 ([be69035](https://github.com/streamich/react-use/commit/be69035caf13f551e7717d3de0ea339c8943a9de))\n* 🎸 improve implementation of useMeasure() hook ([a164843](https://github.com/streamich/react-use/commit/a1648439021a45c781c2074489d7c6aaaa867406))\n* 🎸 improve implementation of useMeasure() hook ([4d88240](https://github.com/streamich/react-use/commit/4d8824064a0afbeba5a15597b007f8463fdbe027))\n* 🎸 mock useMeasure() hook on server and w/o ResizeObserver ([866f3d7](https://github.com/streamich/react-use/commit/866f3d740b08d4772dfbad9c48b3b0b8bac69a28))\n* 🎸 mock useMeasure() hook on server and w/o ResizeObserver ([2bbc73a](https://github.com/streamich/react-use/commit/2bbc73a5f08e9a21bb3054527fc8ff9fd51cfd47))\n* 🎸 remove resize-observer-polyfill from useMeasure ([2a13fba](https://github.com/streamich/react-use/commit/2a13fbae45af3a26c984de03130139181c0c3839))\n* 🎸 remove resize-observer-polyfill from useMeasure ([bf11131](https://github.com/streamich/react-use/commit/bf11131052c4a4ab2b9306486f0b171ac15057b0))\n* Dependencies inference for useCustomCompareEffect ([477c164](https://github.com/streamich/react-use/commit/477c1644a7225513c53294337be3c5b50126712f))\n* improve useAsyncFn and useAsync typings ([85967e2](https://github.com/streamich/react-use/commit/85967e294ce268bd1edc57968f2c3f85a3ee6cb7))\n* keep previous state in useAsyncFn ([54ac91b](https://github.com/streamich/react-use/commit/54ac91b28dca0f5c276b092d563b9c821cbab081))\n* use useReducer in useUpdate hook, instead of useState + useCallback ([6575b14](https://github.com/streamich/react-use/commit/6575b14985ede9b8f45fdad068ee9238d6f7ab80))\n* **useLocalStorage:** add remove feature. ([#229](https://github.com/streamich/react-use/issues/229)) ([587de16](https://github.com/streamich/react-use/commit/587de16ef5c85497d01e63247a578116d0605ff9))\n\n\n### BREAKING CHANGES\n\n* implementation of useMeasure and useLocalStorage changed\n* resize-observer-polyfill package is not used with useMeasure() hook\nanymore.\n* useMeasure() now defaults all values to -1, if they were not set and\ninternal implementation heavily refactored.\n* useAsyncFn now keeps hold of old result/error when called multiple times\n* resize-observer-polyfill package is not used with useMeasure() hook\nanymore.\n* useMeasure() now defaults all values to -1, if they were not set and\ninternal implementation heavily refactored.\n\n# [14.3.0](https://github.com/streamich/react-use/compare/v14.2.0...v14.3.0) (2020-05-16)\n\n\n### Features\n\n* 🎸 add useScratch hook ([2a2a298](https://github.com/streamich/react-use/commit/2a2a298b73f7beb9a2a61c309e649be3d2527473))\n\n# [14.2.0](https://github.com/streamich/react-use/compare/v14.1.1...v14.2.0) (2020-04-24)\n\n\n### Features\n\n* 🎸 onScrubStop provide value where scrub stopped ([138b43c](https://github.com/streamich/react-use/commit/138b43cd1ac9ea7c76a1a42fca48ebdcb94e1006))\n\n## [14.1.1](https://github.com/streamich/react-use/compare/v14.1.0...v14.1.1) (2020-04-11)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @types/js-cookie to v2.2.6 ([f9f4fae](https://github.com/streamich/react-use/commit/f9f4fae6a9a136fdd6763dd2b2214c1746fb0595))\n\n# [14.1.0](https://github.com/streamich/react-use/compare/v14.0.0...v14.1.0) (2020-04-08)\n\n\n### Features\n\n* add useHash hook ([44a6cde](https://github.com/streamich/react-use/commit/44a6cde00e1c74831d7c38b8ae4946f6f2171cf5))\n\n# [14.0.0](https://github.com/streamich/react-use/compare/v13.27.1...v14.0.0) (2020-04-04)\n\n\n### Features\n\n* **useRafLoop:** implement [#1090](https://github.com/streamich/react-use/issues/1090) ([1ef1272](https://github.com/streamich/react-use/commit/1ef1272d6dbe8fbcc2d08223cd80ef32ce28a9c9))\n* **useRafLoop:** reworked the hook, now it do not re-render parent component. ([baa2f75](https://github.com/streamich/react-use/commit/baa2f7511e18fc9fec29376afa27af73de633d8f))\n\n\n### BREAKING CHANGES\n\n* **useRafLoop:** changed return array, now it returns only functions in next order: [stop, start, isActive].\n\nParent component is not re-rendered on loop start/stop.\n\n## [13.27.1](https://github.com/streamich/react-use/compare/v13.27.0...v13.27.1) (2020-03-25)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @xobotyi/scrollbar-width to v1.9.5 ([9751390](https://github.com/streamich/react-use/commit/97513900de7b60d8da62db35125e2f81458a4f25))\n\n# [13.27.0](https://github.com/streamich/react-use/compare/v13.26.5...v13.27.0) (2020-03-03)\n\n\n### Features\n\n* **useSet:** add toggle a method ([#968](https://github.com/streamich/react-use/issues/968)) ([477614f](https://github.com/streamich/react-use/commit/477614f9ef84d3cfa75f9c8a97dbc73d30dd411d))\n\n## [13.26.5](https://github.com/streamich/react-use/compare/v13.26.4...v13.26.5) (2020-03-02)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @xobotyi/scrollbar-width to v1.9.4 ([29d017b](https://github.com/streamich/react-use/commit/29d017b2417f53455ee182aa1ad9574a3ee098d6))\n\n## [13.26.4](https://github.com/streamich/react-use/compare/v13.26.3...v13.26.4) (2020-02-29)\n\n\n### Bug Fixes\n\n* useHoverDirty eslint fix ([0ed6521](https://github.com/streamich/react-use/commit/0ed6521179fe193007f504b3b221a6c5295f9fa0))\n\n## [13.26.3](https://github.com/streamich/react-use/compare/v13.26.2...v13.26.3) (2020-02-26)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @types/js-cookie to v2.2.5 ([1f3217a](https://github.com/streamich/react-use/commit/1f3217a07f0b11ed4d6264687188f587501c133b))\n\n## [13.26.2](https://github.com/streamich/react-use/compare/v13.26.1...v13.26.2) (2020-02-24)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @xobotyi/scrollbar-width to v1.9.3 ([6e2287d](https://github.com/streamich/react-use/commit/6e2287d7e84ef1e455da7209ee32cf86643b00a5))\n\n## [13.26.1](https://github.com/streamich/react-use/compare/v13.26.0...v13.26.1) (2020-02-16)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @xobotyi/scrollbar-width to v1.9.0 ([601d787](https://github.com/streamich/react-use/commit/601d7871a0325677a24a7a93fc9ce2b11132370f))\n\n# [13.26.0](https://github.com/streamich/react-use/compare/v13.25.1...v13.26.0) (2020-02-15)\n\n\n### Bug Fixes\n\n* add initialState to deps ([b394f3d](https://github.com/streamich/react-use/commit/b394f3d72356d331dbce48acd3686bbb64d331b5))\n\n\n### Features\n\n* add useMethods state hook ([7554b9a](https://github.com/streamich/react-use/commit/7554b9a61eb9b4744b9feb113775ff538b16beaf))\n\n## [13.25.1](https://github.com/streamich/react-use/compare/v13.25.0...v13.25.1) (2020-02-15)\n\n\n### Bug Fixes\n\n* 🐛 support default event in useClickAway() ([24281cd](https://github.com/streamich/react-use/commit/24281cdf042da5f83068c6108c67a36fe0cfc74d))\n* generic type on event arg in onClickAway callback on useClickAway ([4ffe454](https://github.com/streamich/react-use/commit/4ffe4542aec840bd6150223489d2c38821954336))\n\n# [13.25.0](https://github.com/streamich/react-use/compare/v13.24.1...v13.25.0) (2020-02-15)\n\n\n### Features\n\n* **useBeforeUnload:** allow passing a dirty function ([#842](https://github.com/streamich/react-use/issues/842)) ([c4a14a4](https://github.com/streamich/react-use/commit/c4a14a4fb370c7628e4cc5861e31cc64a66b64b0))\n\n## [13.24.1](https://github.com/streamich/react-use/compare/v13.24.0...v13.24.1) (2020-02-15)\n\n\n### Performance Improvements\n\n* use fast-deep-equal for deep comparisons ([b9a8aad](https://github.com/streamich/react-use/commit/b9a8aad053a40028f119192ddecedb5c7ec05247))\n\n# [13.24.0](https://github.com/streamich/react-use/compare/v13.23.0...v13.24.0) (2020-02-04)\n\n\n### Features\n\n* add createReducerContext and createStateContext factories ([84b8310](https://github.com/streamich/react-use/commit/84b83101c2253f8935b2804a48ade081e41982a8))\n\n# [13.23.0](https://github.com/streamich/react-use/compare/v13.22.5...v13.23.0) (2020-02-04)\n\n\n### Features\n\n* add createGlobalState hook generator ([fda7199](https://github.com/streamich/react-use/commit/fda7199b7da23f321e68d0784deb1f0f3d273e3c))\n\n## [13.22.5](https://github.com/streamich/react-use/compare/v13.22.4...v13.22.5) (2020-02-04)\n\n\n### Bug Fixes\n\n* 🐛 don't throw in useMediaDevices on missing browser API ([0f119fe](https://github.com/streamich/react-use/commit/0f119fe23e837e0d8c2a8c882b1aaf3b62cbc7d2))\n* handle undefined mediaDevices ([6f68437](https://github.com/streamich/react-use/commit/6f68437359704dace7d518f1f013bc3516400c67))\n\n## [13.22.4](https://github.com/streamich/react-use/compare/v13.22.3...v13.22.4) (2020-01-30)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @xobotyi/scrollbar-width to v1.8.2 ([#930](https://github.com/streamich/react-use/issues/930)) ([727b950](https://github.com/streamich/react-use/commit/727b95096ec6654ba4da22f6825e6d8982258033))\n\n## [13.22.3](https://github.com/streamich/react-use/compare/v13.22.2...v13.22.3) (2020-01-28)\n\n\n### Bug Fixes\n\n* **useIntersection:** disconnect an old IntersectionObserver instance when the ref changes ([ac2f54a](https://github.com/streamich/react-use/commit/ac2f54a8f683296feecfeeb6354738b9ebbc36d0))\n* **useIntersection:** reset an intersectionObserverEntry when the ref changes ([3f8687e](https://github.com/streamich/react-use/commit/3f8687e1f51cc48efbf6be3f0677f5bd06ecba08))\n* **useIntersection:** return null if IntersectionObserver is not supported ([4f6d388](https://github.com/streamich/react-use/commit/4f6d3887be5cf62ce42357a7bf27f4ae8b080eba))\n\n## [13.22.2](https://github.com/streamich/react-use/compare/v13.22.1...v13.22.2) (2020-01-27)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @xobotyi/scrollbar-width to v1.7.0 ([db74101](https://github.com/streamich/react-use/commit/db741019324c3d20a17bbc20a014cedd21e66b1a))\n\n## [13.22.1](https://github.com/streamich/react-use/compare/v13.22.0...v13.22.1) (2020-01-27)\n\n\n### Bug Fixes\n\n* **deps:** update dependency @xobotyi/scrollbar-width to v1.6.0 ([431ba5d](https://github.com/streamich/react-use/commit/431ba5d0816cb7701b03460c5efa5199ad27cbc4))\n\n# [13.22.0](https://github.com/streamich/react-use/compare/v13.21.0...v13.22.0) (2020-01-24)\n\n\n### Bug Fixes\n\n* Fail testing and update doc ([57b9041](https://github.com/streamich/react-use/commit/57b904118e2cd1f1b4e367c9a14e2a981db2f06a))\n\n\n### Features\n\n* add useLongPress hook ([45681b8](https://github.com/streamich/react-use/commit/45681b88e3fd3d9337a38da07248c46ec6d5956e))\n\n# [13.21.0](https://github.com/streamich/react-use/compare/v13.20.0...v13.21.0) (2020-01-20)\n\n\n### Features\n\n* Typings for `useDefault` ([fa0f53b](https://github.com/streamich/react-use/commit/fa0f53bf86a712f4b7e503cdf4718a8ff5448e05))\n\n# [13.20.0](https://github.com/streamich/react-use/compare/v13.19.0...v13.20.0) (2020-01-17)\n\n\n### Features\n\n* `useMap`: allow resetting with provided value other then initial ([7645f72](https://github.com/streamich/react-use/commit/7645f7249dbf52db140dfc8b7866cb4a171e439c))\n\n# [13.19.0](https://github.com/streamich/react-use/compare/v13.18.0...v13.19.0) (2020-01-16)\n\n\n### Features\n\n* add useError hook ([65f3644](https://github.com/streamich/react-use/commit/65f364420524bacebe8f8149b8197fb62bff1a08))\n\n# [13.18.0](https://github.com/streamich/react-use/compare/v13.17.0...v13.18.0) (2020-01-16)\n\n\n### Bug Fixes\n\n* check for null ([d619c39](https://github.com/streamich/react-use/commit/d619c39a21e9f0b4b4bfc6a209311bf0bd495f9b))\n\n\n### Features\n\n* add serializer/deserializer option to useLocalStorage ([5316510](https://github.com/streamich/react-use/commit/5316510babf7606a2f4b78de2b0eb85c930890cf))\n\n# [13.17.0](https://github.com/streamich/react-use/compare/v13.16.1...v13.17.0) (2020-01-15)\n\n\n### Features\n\n* add support for body lock on iOS ([d778408](https://github.com/streamich/react-use/commit/d7784084fe84aca72efe85260101b00ef1df7580))\n\n## [13.16.1](https://github.com/streamich/react-use/compare/v13.16.0...v13.16.1) (2020-01-14)\n\n\n### Bug Fixes\n\n* update the types dep for js-cookie ([5c55d59](https://github.com/streamich/react-use/commit/5c55d59a7d1d799cba7af87e15ab4a4b27a8fc67))\n\n# [13.16.0](https://github.com/streamich/react-use/compare/v13.15.0...v13.16.0) (2020-01-14)\n\n\n### Features\n\n* add option to useTitle to restore title on un-mount ([b8b3e47](https://github.com/streamich/react-use/commit/b8b3e479cea6071d4310bac29f138bd8917eee0b))\n\n# [13.15.0](https://github.com/streamich/react-use/compare/v13.14.3...v13.15.0) (2020-01-13)\n\n\n### Features\n\n* add useCookie hook ([4e5c90f](https://github.com/streamich/react-use/commit/4e5c90f021f56ae2008dc25daad69c43063f608f))\n\n## [13.14.3](https://github.com/streamich/react-use/compare/v13.14.2...v13.14.3) (2020-01-08)\n\n\n### Bug Fixes\n\n* useUpdateEffect cleanup test returns false positive ([9b31c42](https://github.com/streamich/react-use/commit/9b31c42ccb42fe13fc24f7434b00a1bcbee8cd8a))\n* useUpdateEffect test returning false positive ([#865](https://github.com/streamich/react-use/issues/865)) ([1946006](https://github.com/streamich/react-use/commit/1946006c4224bc61eabb797f4cdd7d20fff7ab25))\n\n## [13.14.2](https://github.com/streamich/react-use/compare/v13.14.1...v13.14.2) (2020-01-08)\n\n\n### Bug Fixes\n\n* bump fast-shallow-equal ([19b2b39](https://github.com/streamich/react-use/commit/19b2b39eeae3898bd8d8e3478eb7459372bb09d5))\n\n## [13.14.1](https://github.com/streamich/react-use/compare/v13.14.0...v13.14.1) (2020-01-07)\n\n\n### Bug Fixes\n\n* useUpdateEffect returns optional cleanup function ([0ce421c](https://github.com/streamich/react-use/commit/0ce421ced78fd6eb06a5676fefb856e18bfcacc1))\n* useUpdateEffect returns optional cleanup function ([#864](https://github.com/streamich/react-use/issues/864)) ([7960127](https://github.com/streamich/react-use/commit/7960127a98c0d3c33000088fbd97804d41084f7d))\n\n# [13.14.0](https://github.com/streamich/react-use/compare/v13.13.0...v13.14.0) (2020-01-03)\n\n\n### Features\n\n* 🎸 add [vertical] flag to useSlider() hook ([777865c](https://github.com/streamich/react-use/commit/777865c3ac6772fbda2bc0a6f58cde3eff7dec43))\n\n# [13.13.0](https://github.com/streamich/react-use/compare/v13.12.2...v13.13.0) (2019-12-27)\n\n\n### Features\n\n* add useShallowCompareEffect and useCustomCompareEffect hooks ([ba8803e](https://github.com/streamich/react-use/commit/ba8803eab26d2d48028a4b7120a7354c6d318aea))\n\n## [13.12.2](https://github.com/streamich/react-use/compare/v13.12.1...v13.12.2) (2019-12-10)\n\n\n### Bug Fixes\n\n* **useSet:** \"has\" method in useSet updated to reference latest set object ([4f1d8c2](https://github.com/streamich/react-use/commit/4f1d8c2cbd773f2a26e2eee4fbad88883ea4b405))\n\n## [13.12.1](https://github.com/streamich/react-use/compare/v13.12.0...v13.12.1) (2019-12-09)\n\n\n### Bug Fixes\n\n* **useMap:** methods with side effects should be stable across renders. ([020b4db](https://github.com/streamich/react-use/commit/020b4dbc6c47ab25243ab8af257dd045e6c1bf6d))\n\n# [13.12.0](https://github.com/streamich/react-use/compare/v13.11.0...v13.12.0) (2019-12-09)\n\n\n### Features\n\n* useScrollbarWidth hook; ([#825](https://github.com/streamich/react-use/issues/825)) ([125c7e9](https://github.com/streamich/react-use/commit/125c7e96a188405aea36e94ed1bb3d984232b2f6))\n\n# [13.11.0](https://github.com/streamich/react-use/compare/v13.10.2...v13.11.0) (2019-12-08)\n\n\n### Features\n\n* 🎸 add useUnmountPromise hook ([01421bc](https://github.com/streamich/react-use/commit/01421bc634b941044e95c611f37eb87339486241))\n\n## [13.10.2](https://github.com/streamich/react-use/compare/v13.10.1...v13.10.2) (2019-12-05)\n\n\n### Bug Fixes\n\n* useUpdate hitting maxInt, failing to trigger rerender ([93e7291](https://github.com/streamich/react-use/commit/93e72910abf2dafe5bdff625a21f633afd6e52c5))\n\n## [13.10.1](https://github.com/streamich/react-use/compare/v13.10.0...v13.10.1) (2019-12-03)\n\n\n### Bug Fixes\n\n* \"get\" method in useMap updated to reference latest map object ([044d267](https://github.com/streamich/react-use/commit/044d2677aa474d19da776444b78bd3d2594c6ae5))\n\n# [13.10.0](https://github.com/streamich/react-use/compare/v13.9.0...v13.10.0) (2019-11-28)\n\n\n### Features\n\n* useStateHistory ([#709](https://github.com/streamich/react-use/issues/709)) ([0a66359](https://github.com/streamich/react-use/commit/0a6635914319e9ef7a2902189a3c2dea90a2bf7f))\n\n# [13.9.0](https://github.com/streamich/react-use/compare/v13.8.2...v13.9.0) (2019-11-23)\n\n\n### Features\n\n* add useFirstMountState & useRendersCount hooks ([#769](https://github.com/streamich/react-use/issues/769)) ([30abe2b](https://github.com/streamich/react-use/commit/30abe2b22e3cb7a3e4c6dedd2466d74ce660911d))\n\n## [13.8.2](https://github.com/streamich/react-use/compare/v13.8.1...v13.8.2) (2019-11-22)\n\n\n### Bug Fixes\n\n* **#792:** make useUnmount invoke the current callback version instead of very first ([75284c6](https://github.com/streamich/react-use/commit/75284c62c8e4a68dfeb41a8d98a1e636e9ef531a)), closes [#792](https://github.com/streamich/react-use/issues/792)\n\n## [13.8.1](https://github.com/streamich/react-use/compare/v13.8.0...v13.8.1) (2019-11-21)\n\n\n### Bug Fixes\n\n* useAsyncFn does not discard old promises and might produce races ([022fa0b](https://github.com/streamich/react-use/commit/022fa0b7b77d582a10c6ca61a3dcd901770011c8))\n\n# [13.8.0](https://github.com/streamich/react-use/compare/v13.7.0...v13.8.0) (2019-11-14)\n\n\n### Features\n\n* **useStateValidator:** Refactor method and improve typings; ([436c210](https://github.com/streamich/react-use/commit/436c210f7b577c6958e47df3a244907b07a4db9f))\n\n# [13.7.0](https://github.com/streamich/react-use/compare/v13.6.3...v13.7.0) (2019-11-14)\n\n\n### Features\n\n* Add useSet hook ([095b4de](https://github.com/streamich/react-use/commit/095b4de2321b8bf3431e3f66139629b0495f1ac9))\n\n## [13.6.3](https://github.com/streamich/react-use/compare/v13.6.2...v13.6.3) (2019-11-12)\n\n\n### Bug Fixes\n\n* remove any types in useThrottleFn ([bb5baea](https://github.com/streamich/react-use/commit/bb5baea30cf59721098ca9e3185105bf1b82218b))\n\n## [13.6.2](https://github.com/streamich/react-use/compare/v13.6.1...v13.6.2) (2019-11-11)\n\n\n### Bug Fixes\n\n* restrict useThrottleFn types ([61a83d1](https://github.com/streamich/react-use/commit/61a83d124d35d5606b6c0700faf1361fd3170ca4))\n\n## [13.6.1](https://github.com/streamich/react-use/compare/v13.6.0...v13.6.1) (2019-11-10)\n\n\n### Bug Fixes\n\n* 🐛 check window.Event constructor exists in useLocation ([ad09431](https://github.com/streamich/react-use/commit/ad094311454c48873ba7143654a29b8a0c54459d))\n\n# [13.6.0](https://github.com/streamich/react-use/compare/v13.5.0...v13.6.0) (2019-11-10)\n\n\n### Features\n\n* **useCounter:** `reset` to the newest initialValue ([#667](https://github.com/streamich/react-use/issues/667)) ([e653383](https://github.com/streamich/react-use/commit/e65338372adfccd4800496b377f63bcdf6646788))\n\n# [13.5.0](https://github.com/streamich/react-use/compare/v13.4.0...v13.5.0) (2019-11-08)\n\n\n### Bug Fixes\n\n* **resolveHookState:** by accident removed needed type. ([59aa41c](https://github.com/streamich/react-use/commit/59aa41cff435f5adf7f38d361649761b8dd69794))\n\n\n### Features\n\n* **useList:** reimplemented useList hook; ([1840b57](https://github.com/streamich/react-use/commit/1840b577e2a3d321b8dbb44d5ae443e84d4d9e20))\n\n# [13.4.0](https://github.com/streamich/react-use/compare/v13.3.0...v13.4.0) (2019-11-08)\n\n\n### Features\n\n* **useStateList:** implemented `currentIndex`, `setState`, `setStateAt` methods as requested in [#634](https://github.com/streamich/react-use/issues/634); ([43cb6aa](https://github.com/streamich/react-use/commit/43cb6aa612ae869e24f67acf6f0a1712a65f128b))\n\n# [13.3.0](https://github.com/streamich/react-use/compare/v13.2.2...v13.3.0) (2019-11-06)\n\n\n### Features\n\n* useDebounce add cancel ([693aec8](https://github.com/streamich/react-use/commit/693aec8307c378697c88c635a401832f24d3531a))\n* useDebounce add cancel ([26cab31](https://github.com/streamich/react-use/commit/26cab31f10a995ec45d6c1e2a2f724d9994d801f))\n\n## [13.2.2](https://github.com/streamich/react-use/compare/v13.2.1...v13.2.2) (2019-11-06)\n\n\n### Bug Fixes\n\n* **#749:** now should work with SSR ([c12976c](https://github.com/streamich/react-use/commit/c12976cad26577a4be3ac65133268f41bbdc82da)), closes [#749](https://github.com/streamich/react-use/issues/749)\n\n## [13.2.1](https://github.com/streamich/react-use/compare/v13.2.0...v13.2.1) (2019-11-04)\n\n\n### Bug Fixes\n\n* **yarn.lock:** re-create the yarn.lock file with nailed versions in devDeps ([f094a3a](https://github.com/streamich/react-use/commit/f094a3ae833f406137b9d5355843a6615af20164))\n\n# [13.2.0](https://github.com/streamich/react-use/compare/v13.1.0...v13.2.0) (2019-11-04)\n\n\n### Features\n\n* re-create yarn.lock ([d48e03e](https://github.com/streamich/react-use/commit/d48e03e9ee38555ff29ca46fb6e75c13e9c23aba))\n* re-create yarn.lock ([ccdffe0](https://github.com/streamich/react-use/commit/ccdffe027fba15bdca1f35dc375a0c32739aee6f))\n* **usePreviousDistinct:** add tests for undefined value behaviour; ([cb373f9](https://github.com/streamich/react-use/commit/cb373f951fb3f34b9e54793687de14000a2dc08e))\n* **usePreviousDistinct:** improve types; ([30f53e8](https://github.com/streamich/react-use/commit/30f53e8c5d7e8b27bf3f273ebfcacabf30146ba3))\n* **usePreviousDistinct:** now predicate not called on initial render; ([fbe9b13](https://github.com/streamich/react-use/commit/fbe9b1303c0433d5608ca5b507d9c76711b5cb68))\n* **useStateList:** rework useStateList to make it work properly. ([242c274](https://github.com/streamich/react-use/commit/242c274dd49779fa80f8b9e451c699205279339e))\n* **useTitle:** reworked hook to make it synchronous without useUpdate; ([a133267](https://github.com/streamich/react-use/commit/a13326779ffd6885ac531240b984a77bcad3bee6))\n* **useWindowSize:** A bit changed lyfecycle and added types; ([03bdecf](https://github.com/streamich/react-use/commit/03bdecf7ac6aa0ad863a1efd71c056aa41df62b7))\n\n# [13.1.0](https://github.com/streamich/react-use/compare/v13.0.1...v13.1.0) (2019-11-01)\n\n\n### Features\n\n* pull request template for features ([1dc21f3](https://github.com/streamich/react-use/commit/1dc21f3))\n\n## [13.0.1](https://github.com/streamich/react-use/compare/v13.0.0...v13.0.1) (2019-11-01)\n\n\n### Bug Fixes\n\n* **useLockBodyScroll:** infer overflow type directly from declaration. ([26baf47](https://github.com/streamich/react-use/commit/26baf47))\n\n# [13.0.0](https://github.com/streamich/react-use/compare/v12.13.0...v13.0.0) (2019-11-01)\n\n\n* Merge pull request #711 from streamich/remove-react-wait ([8d40f18](https://github.com/streamich/react-use/commit/8d40f18)), closes [#711](https://github.com/streamich/react-use/issues/711)\n\n\n### Features\n\n* remove useRefMounted hook ([ad74d3d](https://github.com/streamich/react-use/commit/ad74d3d))\n* **useRefMounted:** remove obsolete hook; ([dc364c8](https://github.com/streamich/react-use/commit/dc364c8))\n* **useWait:** removed from package due to it is simple reexport of other package; ([d7c38bd](https://github.com/streamich/react-use/commit/d7c38bd))\n\n\n### BREAKING CHANGES\n\n* useWait hook has been removed from react-use\n* deprecated useRefMounted hook is now removed, use useMountedState hook instead\n\n# [12.13.0](https://github.com/streamich/react-use/compare/v12.12.0...v12.13.0) (2019-10-31)\n\n\n### Features\n\n* **useCounter:** reworked with use of new resolveHookState function plus improved memory usage; ([befcf84](https://github.com/streamich/react-use/commit/befcf84))\n* **useGetSet:** reworked with use of new resolveHookState function plus improved memory usage; ([9b5d0f2](https://github.com/streamich/react-use/commit/9b5d0f2))\n* react-like state resolver to use it in stateful hooks; ([9fd02eb](https://github.com/streamich/react-use/commit/9fd02eb))\n\n# [12.12.0](https://github.com/streamich/react-use/compare/v12.11.0...v12.12.0) (2019-10-31)\n\n\n### Features\n\n* add typings for createReducer ([f1cf036](https://github.com/streamich/react-use/commit/f1cf036))\n\n# [12.11.0](https://github.com/streamich/react-use/compare/v12.10.0...v12.11.0) (2019-10-31)\n\n\n### Features\n\n* **useWait:** add deprecation messages to readme and export; ([d338245](https://github.com/streamich/react-use/commit/d338245))\n\n# [12.10.0](https://github.com/streamich/react-use/compare/v12.9.1...v12.10.0) (2019-10-30)\n\n\n### Features\n\n* **useUpdate:** improve memory usage - now single function instance to increment all counters; ([0f02fd0](https://github.com/streamich/react-use/commit/0f02fd0))\n\n## [12.9.1](https://github.com/streamich/react-use/compare/v12.9.0...v12.9.1) (2019-10-28)\n\n\n### Bug Fixes\n\n* useSize avoid crash in Safari 11 ([da0e66b](https://github.com/streamich/react-use/commit/da0e66b))\n\n# [12.9.0](https://github.com/streamich/react-use/compare/v12.8.0...v12.9.0) (2019-10-26)\n\n\n### Features\n\n* add createBreakpoint ([79ba4ef](https://github.com/streamich/react-use/commit/79ba4ef))\n\n# [12.8.0](https://github.com/streamich/react-use/compare/v12.7.2...v12.8.0) (2019-10-25)\n\n\n### Features\n\n* add ensuredForwardRef and useEnsuredForwardedRef ([1bfe063](https://github.com/streamich/react-use/commit/1bfe063))\n\n## [12.7.2](https://github.com/streamich/react-use/compare/v12.7.1...v12.7.2) (2019-10-23)\n\n\n### Bug Fixes\n\n* 🐛 bump set-harmonic-interval package version ([f7c709a](https://github.com/streamich/react-use/commit/f7c709a))\n\n## [12.7.1](https://github.com/streamich/react-use/compare/v12.7.0...v12.7.1) (2019-10-17)\n\n\n### Bug Fixes\n\n* example in the docs; ([7f54cad](https://github.com/streamich/react-use/commit/7f54cad))\n* rename story's mediator and add `g` flag to it's regex; ([652b318](https://github.com/streamich/react-use/commit/652b318))\n\n# [12.7.0](https://github.com/streamich/react-use/compare/v12.6.0...v12.7.0) (2019-10-17)\n\n\n### Bug Fixes\n\n* error throw tests; ([056875b](https://github.com/streamich/react-use/commit/056875b))\n* useMultiStateValidator readme description; ([8c7f7f5](https://github.com/streamich/react-use/commit/8c7f7f5))\n\n\n### Features\n\n* useMultiStateValidator ([ae26988](https://github.com/streamich/react-use/commit/ae26988))\n\n# [12.6.0](https://github.com/streamich/react-use/compare/v12.5.0...v12.6.0) (2019-10-16)\n\n\n### Features\n\n* useRafState ([#684](https://github.com/streamich/react-use/issues/684)) ([00816a4](https://github.com/streamich/react-use/commit/00816a4))\n\n# [12.5.0](https://github.com/streamich/react-use/compare/v12.4.0...v12.5.0) (2019-10-13)\n\n\n### Features\n\n* useList allow pushing multiple items ([#621](https://github.com/streamich/react-use/issues/621)) ([a624364](https://github.com/streamich/react-use/commit/a624364))\n\n# [12.4.0](https://github.com/streamich/react-use/compare/v12.3.2...v12.4.0) (2019-10-12)\n\n\n### Features\n\n* useIntersection ([#652](https://github.com/streamich/react-use/issues/652)) ([d5f359f](https://github.com/streamich/react-use/commit/d5f359f))\n\n## [12.3.2](https://github.com/streamich/react-use/compare/v12.3.1...v12.3.2) (2019-10-12)\n\n\n### Bug Fixes\n\n* improve use of refs in dependency lists ([#655](https://github.com/streamich/react-use/issues/655)) ([ed8e26d](https://github.com/streamich/react-use/commit/ed8e26d))\n\n## [12.3.1](https://github.com/streamich/react-use/compare/v12.3.0...v12.3.1) (2019-10-10)\n\n\n### Bug Fixes\n\n* move [@types](https://github.com/types)/react-wait to dependencies, closes [#661](https://github.com/streamich/react-use/issues/661) ([#662](https://github.com/streamich/react-use/issues/662)) ([6bdd74e](https://github.com/streamich/react-use/commit/6bdd74e))\n\n# [12.3.0](https://github.com/streamich/react-use/compare/v12.2.3...v12.3.0) (2019-10-07)\n\n\n### Features\n\n* reset util callback for useList ([#654](https://github.com/streamich/react-use/issues/654)) ([9ea3548](https://github.com/streamich/react-use/commit/9ea3548))\n\n## [12.2.3](https://github.com/streamich/react-use/compare/v12.2.2...v12.2.3) (2019-10-05)\n\n\n### Bug Fixes\n\n* move react-wait types to dev dependencies, closes [#644](https://github.com/streamich/react-use/issues/644) ([49372ac](https://github.com/streamich/react-use/commit/49372ac))\n\n## [12.2.2](https://github.com/streamich/react-use/compare/v12.2.1...v12.2.2) (2019-09-26)\n\n\n### Bug Fixes\n\n* useDebounce remove deps from function arguments ([#623](https://github.com/streamich/react-use/issues/623)) ([23d6a5a](https://github.com/streamich/react-use/commit/23d6a5a))\n\n## [12.2.1](https://github.com/streamich/react-use/compare/v12.2.0...v12.2.1) (2019-09-23)\n\n\n### Bug Fixes\n\n* remove attempt from deps of retry in useAsyncRetry ([#614](https://github.com/streamich/react-use/issues/614)) ([adce59e](https://github.com/streamich/react-use/commit/adce59e))\n\n# [12.2.0](https://github.com/streamich/react-use/compare/v12.1.0...v12.2.0) (2019-09-02)\n\n\n### Features\n\n* improve useWindowSize performance rAF ([60a4937](https://github.com/streamich/react-use/commit/60a4937))\n\n# [12.1.0](https://github.com/streamich/react-use/compare/v12.0.0...v12.1.0) (2019-09-01)\n\n\n### Features\n\n* 🎸 add useSearchParam() hook ([b22f32f](https://github.com/streamich/react-use/commit/b22f32f))\n* 🎸 support server-side rendering in useSearchParam() hook ([64ac924](https://github.com/streamich/react-use/commit/64ac924))\n\n# [12.0.0](https://github.com/streamich/react-use/compare/v11.3.2...v12.0.0) (2019-09-01)\n\n\n### Features\n\n* store \"paused\" instead of \"isPlaying\" in media state ([ff900d5](https://github.com/streamich/react-use/commit/ff900d5))\n\n\n### BREAKING CHANGES\n\n* now media players return \"paused\" instead of \"isPlaying\" in their state.\n\n## [11.3.2](https://github.com/streamich/react-use/compare/v11.3.1...v11.3.2) (2019-08-25)\n\n\n### Bug Fixes\n\n* useThrottle & useThrottleFn proper timeout type; ([e2cdb94](https://github.com/streamich/react-use/commit/e2cdb94))\n\n## [11.3.1](https://github.com/streamich/react-use/compare/v11.3.0...v11.3.1) (2019-08-25)\n\n\n### Bug Fixes\n\n* update createReducer to fix initial state ([fd083f2](https://github.com/streamich/react-use/commit/fd083f2))\n\n# [11.3.0](https://github.com/streamich/react-use/compare/v11.2.0...v11.3.0) (2019-08-25)\n\n\n### Features\n\n* add usePreviousDistinct ([#551](https://github.com/streamich/react-use/issues/551)) ([6c3e569](https://github.com/streamich/react-use/commit/6c3e569))\n\n# [11.2.0](https://github.com/streamich/react-use/compare/v11.1.1...v11.2.0) (2019-08-25)\n\n\n### Features\n\n* add useCircularIterate ([8d84340](https://github.com/streamich/react-use/commit/8d84340))\n\n## [11.1.1](https://github.com/streamich/react-use/compare/v11.1.0...v11.1.1) (2019-08-25)\n\n\n### Bug Fixes\n\n* [#550](https://github.com/streamich/react-use/issues/550) ([2617d74](https://github.com/streamich/react-use/commit/2617d74))\n\n# [11.1.0](https://github.com/streamich/react-use/compare/v11.0.2...v11.1.0) (2019-08-25)\n\n\n### Features\n\n* 🎸 add useHarmonicIntervalFn() hook ([d9f21e3](https://github.com/streamich/react-use/commit/d9f21e3))\n\n## [11.0.2](https://github.com/streamich/react-use/compare/v11.0.1...v11.0.2) (2019-08-23)\n\n\n### Bug Fixes\n\n* **useSetState:** memoize setState callback ([0275329](https://github.com/streamich/react-use/commit/0275329))\n* **useSetState:** memoize setState callback ([16f023f](https://github.com/streamich/react-use/commit/16f023f))\n\n## [11.0.1](https://github.com/streamich/react-use/compare/v11.0.0...v11.0.1) (2019-08-23)\n\n\n### Bug Fixes\n\n* correct useSpring() hook behaviour ([d7a622d](https://github.com/streamich/react-use/commit/d7a622d))\n\n# [11.0.0](https://github.com/streamich/react-use/compare/v10.8.0...v11.0.0) (2019-08-22)\n\n\n### Features\n\n* add cancel and reset methods to useTimeout ([283045a](https://github.com/streamich/react-use/commit/283045a))\n* add useTimeoutFn ([284e6fd](https://github.com/streamich/react-use/commit/284e6fd))\n\n\n### BREAKING CHANGES\n\n* useTimeout now returns a tuple\n\n# [10.8.0](https://github.com/streamich/react-use/compare/v10.7.1...v10.8.0) (2019-08-20)\n\n\n### Bug Fixes\n\n* Reworked useBattery hook ([1069060](https://github.com/streamich/react-use/commit/1069060))\n* succeed useRafLoop tests ([09167df](https://github.com/streamich/react-use/commit/09167df))\n\n\n### Features\n\n* 🎸 support useBattery hook on server side ([5d31cf0](https://github.com/streamich/react-use/commit/5d31cf0))\n* 🎸 use only one useState and one useEffect call ([2d0fabf](https://github.com/streamich/react-use/commit/2d0fabf))\n\n## [10.7.1](https://github.com/streamich/react-use/compare/v10.7.0...v10.7.1) (2019-08-20)\n\n\n### Bug Fixes\n\n* async test warnings ([#543](https://github.com/streamich/react-use/issues/543)) ([7af237e](https://github.com/streamich/react-use/commit/7af237e))\n\n# [10.7.0](https://github.com/streamich/react-use/compare/v10.6.4...v10.7.0) (2019-08-19)\n\n\n### Features\n\n* 🎸 add useUpsert ([6875e13](https://github.com/streamich/react-use/commit/6875e13))\n* 🎸 export useUpsert from index ([3eda2b2](https://github.com/streamich/react-use/commit/3eda2b2))\n* add useUpsert ([a7c2899](https://github.com/streamich/react-use/commit/a7c2899))\n\n## [10.6.4](https://github.com/streamich/react-use/compare/v10.6.3...v10.6.4) (2019-08-19)\n\n\n### Bug Fixes\n\n* return from useUpdateEffect ([2f70dc2](https://github.com/streamich/react-use/commit/2f70dc2))\n* useUpdateEffect add return ([8b24df4](https://github.com/streamich/react-use/commit/8b24df4))\n\n## [10.6.3](https://github.com/streamich/react-use/compare/v10.6.2...v10.6.3) (2019-08-19)\n\n\n### Bug Fixes\n\n* allow import default for ESM ([bd3a062](https://github.com/streamich/react-use/commit/bd3a062))\n* rollup build error: Cannot call a namespace ('writeText') ([b3e672b](https://github.com/streamich/react-use/commit/b3e672b))\n\n## [10.6.2](https://github.com/streamich/react-use/compare/v10.6.1...v10.6.2) (2019-08-18)\n\n\n### Bug Fixes\n\n* 🐛 fix master ([d1df7a5](https://github.com/streamich/react-use/commit/d1df7a5))\n\n## [10.6.1](https://github.com/streamich/react-use/compare/v10.6.0...v10.6.1) (2019-08-17)\n\n\n### Bug Fixes\n\n* useUpdateEffect run on the wrong time ([1d5cd10](https://github.com/streamich/react-use/commit/1d5cd10))\n\n# [10.6.0](https://github.com/streamich/react-use/compare/v10.5.0...v10.6.0) (2019-08-17)\n\n\n### Features\n\n* add min/max to useNumber ([586faab](https://github.com/streamich/react-use/commit/586faab))\n\n# [10.5.0](https://github.com/streamich/react-use/compare/v10.4.0...v10.5.0) (2019-08-03)\n\n\n### Features\n\n* add useRafLoop hook ([be7d7c3](https://github.com/streamich/react-use/commit/be7d7c3))\n\n# [10.4.0](https://github.com/streamich/react-use/compare/v10.3.1...v10.4.0) (2019-08-02)\n\n\n### Features\n\n* add useMountedState hook ([9081b99](https://github.com/streamich/react-use/commit/9081b99))\n\n## [10.3.1](https://github.com/streamich/react-use/compare/v10.3.0...v10.3.1) (2019-08-02)\n\n\n### Bug Fixes\n\n* **storybook:** fix useKeyboardJs import path ([b7481f6](https://github.com/streamich/react-use/commit/b7481f6))\n* **useKeyboardJs:** fix argument type error ([8c820ce](https://github.com/streamich/react-use/commit/8c820ce))\n* allow string list in useKeyboardJs hook ([aecbd0b](https://github.com/streamich/react-use/commit/aecbd0b))\n\n# [10.3.0](https://github.com/streamich/react-use/compare/v10.2.0...v10.3.0) (2019-07-26)\n\n\n### Features\n\n* add useDefault hook ([ade0557](https://github.com/streamich/react-use/commit/ade0557))\n\n# [10.2.0](https://github.com/streamich/react-use/compare/v10.1.2...v10.2.0) (2019-07-25)\n\n\n### Features\n\n* useWindowScroll - for cross-browser compatibility ([5987cc8](https://github.com/streamich/react-use/commit/5987cc8))\n* useWindowScroll - for cross-browser compatibility ([#480](https://github.com/streamich/react-use/issues/480)) ([e37dd8d](https://github.com/streamich/react-use/commit/e37dd8d))\n\n## [10.1.2](https://github.com/streamich/react-use/compare/v10.1.1...v10.1.2) (2019-07-21)\n\n\n### Bug Fixes\n\n* remove OpenCollective postinstall hook ([26dcebc](https://github.com/streamich/react-use/commit/26dcebc))\n\n## [10.1.1](https://github.com/streamich/react-use/compare/v10.1.0...v10.1.1) (2019-07-21)\n\n\n### Bug Fixes\n\n* useMouse & useMouseHovered type definitions for SVG ([9e97451](https://github.com/streamich/react-use/commit/9e97451))\n* useMouse & useMouseHovered type definitions for SVG ([#479](https://github.com/streamich/react-use/issues/479)) ([e2e4a60](https://github.com/streamich/react-use/commit/e2e4a60))\n\n# [10.1.0](https://github.com/streamich/react-use/compare/v10.0.0...v10.1.0) (2019-07-17)\n\n\n### Features\n\n* add latest `react-wait` types ([6ebe3bb](https://github.com/streamich/react-use/commit/6ebe3bb))\n\n# [10.0.0](https://github.com/streamich/react-use/compare/v9.12.0...v10.0.0) (2019-07-17)\n\n\n### Features\n\n* remove big libs from peerDependencies ([1dbdc5d](https://github.com/streamich/react-use/commit/1dbdc5d))\n\n\n### BREAKING CHANGES\n\n* `useSpring` and `useKeyboardJs` hooks need to be imported directly now and libs they depend on are not in peerDependencies anymore.\n\n# [9.12.0](https://github.com/streamich/react-use/compare/v9.11.2...v9.12.0) (2019-07-16)\n\n\n### Bug Fixes\n\n* 🐛 fix useDebounce import ([40b33da](https://github.com/streamich/react-use/commit/40b33da))\n\n\n### Features\n\n* add useInterval hook ([6645ed9](https://github.com/streamich/react-use/commit/6645ed9))\n\n## [9.11.2](https://github.com/streamich/react-use/compare/v9.11.1...v9.11.2) (2019-07-16)\n\n\n### Bug Fixes\n\n* support useMedia usage server-side ([50a5160](https://github.com/streamich/react-use/commit/50a5160))\n\n## [9.11.1](https://github.com/streamich/react-use/compare/v9.11.0...v9.11.1) (2019-07-16)\n\n\n### Bug Fixes\n\n* createReducer stable dispatch function identity ([9780545](https://github.com/streamich/react-use/commit/9780545))\n\n# [9.11.0](https://github.com/streamich/react-use/compare/v9.10.0...v9.11.0) (2019-07-11)\n\n\n### Features\n\n* useMedia - initialize state with call to media query ([#454](https://github.com/streamich/react-use/issues/454)) ([ab81897](https://github.com/streamich/react-use/commit/ab81897))\n\n# [9.10.0](https://github.com/streamich/react-use/compare/v9.9.0...v9.10.0) (2019-07-10)\n\n\n### Features\n\n* expose useIsomorphicLayoutEffect + docs ([#451](https://github.com/streamich/react-use/issues/451)) ([8dcbbf1](https://github.com/streamich/react-use/commit/8dcbbf1))\n\n# [9.9.0](https://github.com/streamich/react-use/compare/v9.8.3...v9.9.0) (2019-07-10)\n\n\n### Features\n\n* add usePermission ([4da40b9](https://github.com/streamich/react-use/commit/4da40b9))\n* usePermission ([588a0c5](https://github.com/streamich/react-use/commit/588a0c5))\n\n## [9.8.3](https://github.com/streamich/react-use/compare/v9.8.2...v9.8.3) (2019-07-10)\n\n\n### Bug Fixes\n\n* useLocalStorage types for functional updates ([e2b8278](https://github.com/streamich/react-use/commit/e2b8278))\n\n## [9.8.2](https://github.com/streamich/react-use/compare/v9.8.1...v9.8.2) (2019-07-08)\n\n\n### Bug Fixes\n\n* **useSize:** prevents accessing iframe's property when it's not defined ([c9b5cdc](https://github.com/streamich/react-use/commit/c9b5cdc)), closes [#442](https://github.com/streamich/react-use/issues/442)\n* **useSize:** prevents accessing iframe's property when it's not… ([#443](https://github.com/streamich/react-use/issues/443)) ([8f04e8f](https://github.com/streamich/react-use/commit/8f04e8f))\n* iframe can be null ([a9e3bab](https://github.com/streamich/react-use/commit/a9e3bab))\n\n## [9.8.1](https://github.com/streamich/react-use/compare/v9.8.0...v9.8.1) (2019-06-30)\n\n\n### Bug Fixes\n\n* lint fixes via lint:fix ([7ce8e4f](https://github.com/streamich/react-use/commit/7ce8e4f))\n* useMap uses prevMap state which is safer ([3554f79](https://github.com/streamich/react-use/commit/3554f79))\n* **useMap:** remove now also uses prevMap state to not overwrite or lose state ([0a59869](https://github.com/streamich/react-use/commit/0a59869))\n\n# [9.8.0](https://github.com/streamich/react-use/compare/v9.7.2...v9.8.0) (2019-06-30)\n\n\n### Bug Fixes\n\n* 🐛 fix test and add pre-push hook ([1353b6c](https://github.com/streamich/react-use/commit/1353b6c))\n\n\n### Features\n\n* add voice option in use speech ([6dc2dd5](https://github.com/streamich/react-use/commit/6dc2dd5))\n* add voice option in useSpeech ([#422](https://github.com/streamich/react-use/issues/422)) ([c32d02b](https://github.com/streamich/react-use/commit/c32d02b))\n\n## [9.7.2](https://github.com/streamich/react-use/compare/v9.7.1...v9.7.2) (2019-06-27)\n\n\n### Bug Fixes\n\n* save to localStorage only when state changes ([ba6d375](https://github.com/streamich/react-use/commit/ba6d375))\n* use correct list variable in useList ([#412](https://github.com/streamich/react-use/issues/412)) ([b937296](https://github.com/streamich/react-use/commit/b937296))\n\n## [9.7.1](https://github.com/streamich/react-use/compare/v9.7.0...v9.7.1) (2019-06-23)\n\n\n### Bug Fixes\n\n* 🐛 use synchronouse effect to subscribe to observables ([376eea3](https://github.com/streamich/react-use/commit/376eea3))\n\n# [9.7.0](https://github.com/streamich/react-use/compare/v9.6.0...v9.7.0) (2019-06-19)\n\n\n### Features\n\n* improve useClickAway() hook ([#394](https://github.com/streamich/react-use/issues/394)) ([c60df19](https://github.com/streamich/react-use/commit/c60df19))\n\n# [9.6.0](https://github.com/streamich/react-use/compare/v9.5.0...v9.6.0) (2019-06-18)\n\n\n### Bug Fixes\n\n* add additional ref check on clean up ([d18d2d8](https://github.com/streamich/react-use/commit/d18d2d8))\n* always return something from effect ([3355426](https://github.com/streamich/react-use/commit/3355426))\n\n\n### Features\n\n* 🎸 add useScrolling hook ([bd9928e](https://github.com/streamich/react-use/commit/bd9928e))\n* 🎸 add useScrolling hook to index ([b3ba702](https://github.com/streamich/react-use/commit/b3ba702))\n* add useScrolling docs ([25a93f6](https://github.com/streamich/react-use/commit/25a93f6))\n* add useScrolling story ([760edf1](https://github.com/streamich/react-use/commit/760edf1))\n\n# [9.5.0](https://github.com/streamich/react-use/compare/v9.4.1...v9.5.0) (2019-06-16)\n\n\n### Bug Fixes\n\n* add missing `rate` property ([fb795a6](https://github.com/streamich/react-use/commit/fb795a6))\n\n\n### Features\n\n* add rate option in useSpeech ([f52f1f7](https://github.com/streamich/react-use/commit/f52f1f7))\n* add rate option in useSpeech ([#399](https://github.com/streamich/react-use/issues/399)) ([0e4ebc6](https://github.com/streamich/react-use/commit/0e4ebc6))\n\n## [9.4.1](https://github.com/streamich/react-use/compare/v9.4.0...v9.4.1) (2019-06-12)\n\n\n### Bug Fixes\n\n* fix Storybook docs Markdown import ([962a312](https://github.com/streamich/react-use/commit/962a312))\n\n# [9.4.0](https://github.com/streamich/react-use/compare/v9.3.0...v9.4.0) (2019-06-04)\n\n\n### Bug Fixes\n\n* fix TypeScript error ([72e3036](https://github.com/streamich/react-use/commit/72e3036))\n* **docs:** syntax error, improve examples ([8bbe9d8](https://github.com/streamich/react-use/commit/8bbe9d8))\n\n\n### Features\n\n* improve createReducer function ([6ba2d93](https://github.com/streamich/react-use/commit/6ba2d93)), closes [#164](https://github.com/streamich/react-use/issues/164)\n\n# [9.3.0](https://github.com/streamich/react-use/compare/v9.2.0...v9.3.0) (2019-05-31)\n\n\n### Features\n\n* improve useAsync and useAsyncFn ([3ab1d5d](https://github.com/streamich/react-use/commit/3ab1d5d))\n\n# [9.2.0](https://github.com/streamich/react-use/compare/v9.1.2...v9.2.0) (2019-05-31)\n\n\n### Features\n\n* 🎸 improve useObservable() type annotations ([d0c3713](https://github.com/streamich/react-use/commit/d0c3713))\n* improve useSetState() typings ([fad4440](https://github.com/streamich/react-use/commit/fad4440))\n\n## [9.1.2](https://github.com/streamich/react-use/compare/v9.1.1...v9.1.2) (2019-05-24)\n\n\n### Bug Fixes\n\n* **useAudio:** src change should reset isPlaying state ([65bffca](https://github.com/streamich/react-use/commit/65bffca))\n\n## [9.1.1](https://github.com/streamich/react-use/compare/v9.1.0...v9.1.1) (2019-05-24)\n\n\n### Bug Fixes\n\n* **useMap:** more stringent type ([7bbbe47](https://github.com/streamich/react-use/commit/7bbbe47))\n\n# [9.1.0](https://github.com/streamich/react-use/compare/v9.0.0...v9.1.0) (2019-05-24)\n\n\n### Features\n\n* pass arguments to useAsyncFn function ([6789d10](https://github.com/streamich/react-use/commit/6789d10))\n\n# [9.0.0](https://github.com/streamich/react-use/compare/v8.4.0...v9.0.0) (2019-05-09)\n\n\n### Features\n\n* improve useToggle interface ([81b1cac](https://github.com/streamich/react-use/commit/81b1cac))\n\n\n### BREAKING CHANGES\n\n* useToggle interface changed\n\n# [8.4.0](https://github.com/streamich/react-use/compare/v8.3.1...v8.4.0) (2019-05-07)\n\n\n### Features\n\n* add usePrevious hook ([4861a39](https://github.com/streamich/react-use/commit/4861a39))\n\n## [8.3.1](https://github.com/streamich/react-use/compare/v8.3.0...v8.3.1) (2019-04-29)\n\n\n### Bug Fixes\n\n* **useRefMounted:** only run and cleanup once ([6a651be](https://github.com/streamich/react-use/commit/6a651be))\n\n# [8.3.0](https://github.com/streamich/react-use/compare/v8.2.0...v8.3.0) (2019-04-29)\n\n\n### Features\n\n* add type define for createMemo ([6638c1a](https://github.com/streamich/react-use/commit/6638c1a))\n\n# [8.2.0](https://github.com/streamich/react-use/compare/v8.1.4...v8.2.0) (2019-04-23)\n\n\n### Bug Fixes\n\n* make options useGeolocation optional ([01959a1](https://github.com/streamich/react-use/commit/01959a1))\n\n\n### Features\n\n* support options for useGeolocation ([7d4c59e](https://github.com/streamich/react-use/commit/7d4c59e))\n\n## [8.1.4](https://github.com/streamich/react-use/compare/v8.1.3...v8.1.4) (2019-04-23)\n\n\n### Bug Fixes\n\n* 🐛 support click away on iOS, allow user to chose events ([f14e1d7](https://github.com/streamich/react-use/commit/f14e1d7))\n\n## [8.1.3](https://github.com/streamich/react-use/compare/v8.1.2...v8.1.3) (2019-04-18)\n\n\n### Bug Fixes\n\n* 🐛 don't fire typing event on modifier keys pressed ([ce76edf](https://github.com/streamich/react-use/commit/ce76edf))\n\n## [8.1.2](https://github.com/streamich/react-use/compare/v8.1.1...v8.1.2) (2019-04-12)\n\n\n### Bug Fixes\n\n* **useIdle:** include 'ms' prop in uesEffect dependencies ([7a670a2](https://github.com/streamich/react-use/commit/7a670a2))\n\n## [8.1.1](https://github.com/streamich/react-use/compare/v8.1.0...v8.1.1) (2019-04-09)\n\n\n### Bug Fixes\n\n* 🐛 make useLocation work on server, improve hook ([6f6030a](https://github.com/streamich/react-use/commit/6f6030a))\n\n# [8.1.0](https://github.com/streamich/react-use/compare/v8.0.0...v8.1.0) (2019-04-08)\n\n\n### Features\n\n* add useAsyncCallback hook ([c6ecb36](https://github.com/streamich/react-use/commit/c6ecb36))\n\n# [8.0.0](https://github.com/streamich/react-use/compare/v7.6.0...v8.0.0) (2019-04-08)\n\n\n### Features\n\n* change useCopyToClipboard implementation ([c391038](https://github.com/streamich/react-use/commit/c391038))\n\n\n### BREAKING CHANGES\n\n* useCopyToClipboard interface changed\n\n# [7.6.0](https://github.com/streamich/react-use/compare/v7.5.0...v7.6.0) (2019-04-07)\n\n\n### Bug Fixes\n\n* 🐛 handle case when activeElement is empty ([3d83705](https://github.com/streamich/react-use/commit/3d83705))\n\n\n### Features\n\n* 🎸 add useStartTypings hook ([5fda2e0](https://github.com/streamich/react-use/commit/5fda2e0))\n\n# [7.5.0](https://github.com/streamich/react-use/compare/v7.4.0...v7.5.0) (2019-04-07)\n\n\n### Features\n\n* 🎸 add onCopy and onError events and use NPM copy library ([2553225](https://github.com/streamich/react-use/commit/2553225))\n* 🎸 improve useCopyToClipboard() hook ([f185044](https://github.com/streamich/react-use/commit/f185044))\n* 🎸 make useCopyToClipboard hook interface more idiomatic ([0a6d773](https://github.com/streamich/react-use/commit/0a6d773))\n* add useCopyToClipboard() hook ([4d8e276](https://github.com/streamich/react-use/commit/4d8e276))\n\n# [7.4.0](https://github.com/streamich/react-use/compare/v7.3.1...v7.4.0) (2019-04-07)\n\n\n### Features\n\n* add useDeepCompareEffect hook ([77e015b](https://github.com/streamich/react-use/commit/77e015b))\n\n## [7.3.1](https://github.com/streamich/react-use/compare/v7.3.0...v7.3.1) (2019-03-31)\n\n\n### Bug Fixes\n\n* 🐛 call key{up/donw} callbacks in useKeyPressEvent correct ([60064a6](https://github.com/streamich/react-use/commit/60064a6))\n\n# [7.3.0](https://github.com/streamich/react-use/compare/v7.2.0...v7.3.0) (2019-03-31)\n\n\n### Features\n\n* add useEffectOnce hook ([06c12d4](https://github.com/streamich/react-use/commit/06c12d4))\n\n# [7.2.0](https://github.com/streamich/react-use/compare/v7.1.1...v7.2.0) (2019-03-31)\n\n\n### Features\n\n* default dependency array for useAsync and useAsyncRetry ([cb140a0](https://github.com/streamich/react-use/commit/cb140a0))\n\n## [7.1.1](https://github.com/streamich/react-use/compare/v7.1.0...v7.1.1) (2019-03-30)\n\n\n### Bug Fixes\n\n* consistent refs in useFullscreen hook ([dc85499](https://github.com/streamich/react-use/commit/dc85499))\n\n# [7.1.0](https://github.com/streamich/react-use/compare/v7.0.2...v7.1.0) (2019-03-29)\n\n\n### Bug Fixes\n\n* useClickAway TypeScript typings ([4b20083](https://github.com/streamich/react-use/commit/4b20083))\n\n\n### Features\n\n* pass click event in useClickAway to user ([01e38bc](https://github.com/streamich/react-use/commit/01e38bc))\n\n## [7.0.2](https://github.com/streamich/react-use/compare/v7.0.1...v7.0.2) (2019-03-29)\n\n\n### Bug Fixes\n\n* 🐛 add rebound and keyboards deps back to peerDependencies ([4fc46aa](https://github.com/streamich/react-use/commit/4fc46aa))\n\n## [7.0.1](https://github.com/streamich/react-use/compare/v7.0.0...v7.0.1) (2019-03-29)\n\n\n### Bug Fixes\n\n* add optional attributes in AsyncState ([b0c9770](https://github.com/streamich/react-use/commit/b0c9770))\n\n# [7.0.0](https://github.com/streamich/react-use/compare/v6.2.2...v7.0.0) (2019-03-28)\n\n\n### Bug Fixes\n\n* 🐛 fix TypeScript build errors ([5c95f28](https://github.com/streamich/react-use/commit/5c95f28))\n* 🐛 make sure all paths in usePageLeave return ([6655092](https://github.com/streamich/react-use/commit/6655092))\n* 🐛 track \"over\" state better in useDrop hook ([acc355c](https://github.com/streamich/react-use/commit/acc355c))\n\n\n### Features\n\n* 🎸 add clear() to useList, use fn for state updates ([b20cf7c](https://github.com/streamich/react-use/commit/b20cf7c))\n* 🎸 add createRenderProp function for creating render-props ([f4fd748](https://github.com/streamich/react-use/commit/f4fd748))\n* 🎸 add useDrop hook ([6e415cf](https://github.com/streamich/react-use/commit/6e415cf))\n* 🎸 add useDropArea hook ([676d0de](https://github.com/streamich/react-use/commit/676d0de))\n* 🎸 add useEvent hook ([2a13cfb](https://github.com/streamich/react-use/commit/2a13cfb))\n* 🎸 add useKey hook ([299fd86](https://github.com/streamich/react-use/commit/299fd86))\n* 🎸 add useKeyboardJs hook ([3516aa6](https://github.com/streamich/react-use/commit/3516aa6))\n* 🎸 add usePageLeave hook ([33ac91b](https://github.com/streamich/react-use/commit/33ac91b))\n* 🎸 add useThrottleFn hook that throttles function ([0ccdf95](https://github.com/streamich/react-use/commit/0ccdf95))\n* 🎸 improve useFullscreen hook ([7c38165](https://github.com/streamich/react-use/commit/7c38165))\n* 🎸 keep keyboard events in useKeyPress hook ([00fecab](https://github.com/streamich/react-use/commit/00fecab))\n* 🎸 refactor useKeyPressEvent hook ([c0658f6](https://github.com/streamich/react-use/commit/c0658f6))\n* 🎸 return events from useKeyboardJs hook ([aa277b8](https://github.com/streamich/react-use/commit/aa277b8))\n* 🎸 simplify and improve useThrottle hook ([452e8d9](https://github.com/streamich/react-use/commit/452e8d9))\n* 🎸 useKeyPress hook now uses useKey, KeyboardJS removed ([727743b](https://github.com/streamich/react-use/commit/727743b))\n\n\n### BREAKING CHANGES\n\n* 🧨 useKeyPressEvent hook modified for dependency injection and providing\nevent objects to user\n* 🧨 KeyboardJS now available anymore in useKeyPress hook, instead it will be\na separate useKeyPressKJ hook.\n* 🧨 useThrottle is now a completely different hook\n\n## [6.2.2](https://github.com/streamich/react-use/compare/v6.2.1...v6.2.2) (2019-03-28)\n\n\n### Bug Fixes\n\n* fix deps arg and union type in useAsync and useAsyncRetry ([929e726](https://github.com/streamich/react-use/commit/929e726))\n\n## [6.2.1](https://github.com/streamich/react-use/compare/v6.2.0...v6.2.1) (2019-03-27)\n\n\n### Bug Fixes\n\n* set 'module' field properly ([35d4fc2](https://github.com/streamich/react-use/commit/35d4fc2))\n\n# [6.2.0](https://github.com/streamich/react-use/compare/v6.1.0...v6.2.0) (2019-03-27)\n\n\n### Bug Fixes\n\n* add esm to 'files' in package.json ([fc1ba07](https://github.com/streamich/react-use/commit/fc1ba07))\n* clean esm folder as well ([0a10a6e](https://github.com/streamich/react-use/commit/0a10a6e))\n\n\n### Features\n\n* emit code in ES Module mode ([464642e](https://github.com/streamich/react-use/commit/464642e))\n\n# [6.1.0](https://github.com/streamich/react-use/compare/v6.0.0...v6.1.0) (2019-03-26)\n\n\n### Features\n\n* add useThrottle hook ([756bc99](https://github.com/streamich/react-use/commit/756bc99))\n\n# [6.0.0](https://github.com/streamich/react-use/compare/v5.16.1...v6.0.0) (2019-03-26)\n\n\n### Bug Fixes\n\n* 🐛 bump nano-css ([f1f36dc](https://github.com/streamich/react-use/commit/f1f36dc)), closes [#90](https://github.com/streamich/react-use/issues/90)\n* 🐛 don't throw only in development ([f5faba5](https://github.com/streamich/react-use/commit/f5faba5))\n\n\n### chore\n\n* 🤖 don't install only large dependencies ([6170067](https://github.com/streamich/react-use/commit/6170067))\n\n\n### Features\n\n* 🎸 add {bound} option to useMouse ([9bb02a1](https://github.com/streamich/react-use/commit/9bb02a1))\n* 🎸 implement useClickAway, remove useOutsideClick ([a03143a](https://github.com/streamich/react-use/commit/a03143a))\n* 🎸 keep global state of all useLockBodyScroll hooks ([5dd10e9](https://github.com/streamich/react-use/commit/5dd10e9))\n* 🎸 move extra mouse functionality into useMouseHovered ([8b0580e](https://github.com/streamich/react-use/commit/8b0580e))\n* more precise size for useMouse ([b887075](https://github.com/streamich/react-use/commit/b887075))\n\n\n### BREAKING CHANGES\n\n* 🧨 error is logged instead of thrown in development environment\n* 🧨 useOutsideClick is now useClickAway\n* 🧨 useCallbag hook is removed, some hooks KeyboardJS and Rebound installed\nseparately\n\n## [5.16.1](https://github.com/streamich/react-use/compare/v5.16.0...v5.16.1) (2019-03-26)\n\n\n### Bug Fixes\n\n* types for useGeolocation ([b72c098](https://github.com/streamich/react-use/commit/b72c098))\n\n# [5.16.0](https://github.com/streamich/react-use/compare/v5.15.0...v5.16.0) (2019-03-25)\n\n\n### Features\n\n* more precise size for useMouse ([1761031](https://github.com/streamich/react-use/commit/1761031))\n\n# [5.15.0](https://github.com/streamich/react-use/compare/v5.14.0...v5.15.0) (2019-03-25)\n\n\n### Features\n\n* add useMouse hook ([17dfa8e](https://github.com/streamich/react-use/commit/17dfa8e))\n\n# [5.14.0](https://github.com/streamich/react-use/compare/v5.13.0...v5.14.0) (2019-03-24)\n\n\n### Features\n\n* 🎸 keep global state of all useLockBodyScroll hooks ([9bb7047](https://github.com/streamich/react-use/commit/9bb7047))\n* add useLockBodyScroll hook ([d990db4](https://github.com/streamich/react-use/commit/d990db4))\n\n# [5.13.0](https://github.com/streamich/react-use/compare/v5.12.1...v5.13.0) (2019-03-23)\n\n\n### Features\n\n* add useScroll hook ([a92e9b2](https://github.com/streamich/react-use/commit/a92e9b2))\n\n## [5.12.1](https://github.com/streamich/react-use/compare/v5.12.0...v5.12.1) (2019-03-23)\n\n\n### Bug Fixes\n\n* 🐛 cancel animation frame on un-mount in useWindowScroll() ([bc021ce](https://github.com/streamich/react-use/commit/bc021ce))\n\n# [5.12.0](https://github.com/streamich/react-use/compare/v5.11.0...v5.12.0) (2019-03-23)\n\n\n### Features\n\n* add useWindowScroll hook ([076d0de](https://github.com/streamich/react-use/commit/076d0de))\n\n# [5.11.0](https://github.com/streamich/react-use/compare/v5.10.0...v5.11.0) (2019-03-22)\n\n\n### Features\n\n* 🎸 refresh useCss hook ([0116cc9](https://github.com/streamich/react-use/commit/0116cc9))\n\n# [5.10.0](https://github.com/streamich/react-use/compare/v5.9.0...v5.10.0) (2019-03-21)\n\n\n### Features\n\n* add useUpdateEffect hook ([c2afd23](https://github.com/streamich/react-use/commit/c2afd23))\n\n# [5.9.0](https://github.com/streamich/react-use/compare/v5.8.1...v5.9.0) (2019-03-21)\n\n\n### Features\n\n* add useAsyncRetry hook ([576cf42](https://github.com/streamich/react-use/commit/576cf42))\n\n\n### Performance Improvements\n\n* remove asyn/await wrapper ([8e3de1c](https://github.com/streamich/react-use/commit/8e3de1c))\n\n## [5.8.1](https://github.com/streamich/react-use/compare/v5.8.0...v5.8.1) (2019-03-20)\n\n\n### Bug Fixes\n\n* 🐛 use useLayoutEffect() in useCss() to inject CSS quick ([7328f26](https://github.com/streamich/react-use/commit/7328f26))\n\n# [5.8.0](https://github.com/streamich/react-use/compare/v5.7.1...v5.8.0) (2019-03-19)\n\n\n### Features\n\n* release useKeyPressEvent() ([96798e2](https://github.com/streamich/react-use/commit/96798e2))\n\n## [5.7.1](https://github.com/streamich/react-use/compare/v5.7.0...v5.7.1) (2019-03-15)\n\n\n### Bug Fixes\n\n* 🐛 allow every promise in usePromise() hook have own type ([d60fef7](https://github.com/streamich/react-use/commit/d60fef7))\n\n# [5.7.0](https://github.com/streamich/react-use/compare/v5.6.0...v5.7.0) (2019-03-15)\n\n\n### Bug Fixes\n\n* 🐛 fix TypeScript typings for usePromise() ([ba0acb6](https://github.com/streamich/react-use/commit/ba0acb6))\n\n\n### Features\n\n* 🎸 add usePromise() hook ([aad368b](https://github.com/streamich/react-use/commit/aad368b))\n\n# [5.6.0](https://github.com/streamich/react-use/compare/v5.5.6...v5.6.0) (2019-03-13)\n\n\n### Features\n\n* transpile down to ES5 ([61382e3](https://github.com/streamich/react-use/commit/61382e3))\n\n## [5.5.6](https://github.com/streamich/react-use/compare/v5.5.5...v5.5.6) (2019-03-11)\n\n\n### Bug Fixes\n\n* correct createMemo.md ([4e2d639](https://github.com/streamich/react-use/commit/4e2d639))\n* correct createMemo.story ([9c8e093](https://github.com/streamich/react-use/commit/9c8e093))\n\n## [5.5.5](https://github.com/streamich/react-use/compare/v5.5.4...v5.5.5) (2019-03-04)\n\n\n### Bug Fixes\n\n* 🐛 make useWindowSize work on server ([8f93853](https://github.com/streamich/react-use/commit/8f93853))\n\n## [5.5.4](https://github.com/streamich/react-use/compare/v5.5.3...v5.5.4) (2019-02-25)\n\n\n### Bug Fixes\n\n* 🐛 new React behaviour needs useState to set something ([e926faf](https://github.com/streamich/react-use/commit/e926faf)), closes [#128](https://github.com/streamich/react-use/issues/128)\n\n## [5.5.3](https://github.com/streamich/react-use/compare/v5.5.2...v5.5.3) (2019-02-25)\n\n\n### Bug Fixes\n\n* **deps:** update dependency use-callbag to ^0.2.0 ([4d49d0b](https://github.com/streamich/react-use/commit/4d49d0b))\n\n## [5.5.2](https://github.com/streamich/react-use/compare/v5.5.1...v5.5.2) (2019-02-24)\n\n\n### Bug Fixes\n\n* **deps:** update dependency use-onclickoutside to ^0.3.0 ([0baae6d](https://github.com/streamich/react-use/commit/0baae6d))\n\n## [5.5.1](https://github.com/streamich/react-use/compare/v5.5.0...v5.5.1) (2019-02-24)\n\n\n### Bug Fixes\n\n* **deps:** update dependency ts-easing to ^0.2.0 ([3321e11](https://github.com/streamich/react-use/commit/3321e11))\n\n# [5.5.0](https://github.com/streamich/react-use/compare/v5.4.1...v5.5.0) (2019-02-23)\n\n\n### Bug Fixes\n\n* add type definition for useList() remove() method ([ea2dc43](https://github.com/streamich/react-use/commit/ea2dc43))\n* useSetState bug ([83611a1](https://github.com/streamich/react-use/commit/83611a1))\n\n\n### Features\n\n* Add remove method for useList ([5a295d9](https://github.com/streamich/react-use/commit/5a295d9))\n\n## [5.4.1](https://github.com/streamich/react-use/compare/v5.4.0...v5.4.1) (2019-02-19)\n\n\n### Bug Fixes\n\n* 🐛 better async loading for keyboardjs ([2096bae](https://github.com/streamich/react-use/commit/2096bae)), closes [#103](https://github.com/streamich/react-use/issues/103)\n\n# [5.4.0](https://github.com/streamich/react-use/compare/v5.3.1...v5.4.0) (2019-02-19)\n\n\n### Features\n\n* add error and loading fields to useGeolocation ([6909a69](https://github.com/streamich/react-use/commit/6909a69))\n\n## [5.3.1](https://github.com/streamich/react-use/compare/v5.3.0...v5.3.1) (2019-02-17)\n\n\n### Bug Fixes\n\n* 🐛 fix typings in useOrientation sensor ([afbacac](https://github.com/streamich/react-use/commit/afbacac))\n* 🐛 fix useSetState after React update ([524abe5](https://github.com/streamich/react-use/commit/524abe5)), closes [#107](https://github.com/streamich/react-use/issues/107) [#107](https://github.com/streamich/react-use/issues/107)\n* useOrientation breaks in some devices ([d89bd54](https://github.com/streamich/react-use/commit/d89bd54))\n\n# [5.3.0](https://github.com/streamich/react-use/compare/v5.2.3...v5.3.0) (2019-02-07)\n\n\n### Features\n\n* Add updateAt method for useList ([ad05609](https://github.com/streamich/react-use/commit/ad05609))\n\n## [5.2.3](https://github.com/streamich/react-use/compare/v5.2.2...v5.2.3) (2019-02-07)\n\n\n### Bug Fixes\n\n* 🐛 fix build and update React deps ([27e26a0](https://github.com/streamich/react-use/commit/27e26a0))\n\n## [5.2.2](https://github.com/streamich/react-use/compare/v5.2.1...v5.2.2) (2019-02-02)\n\n\n### Bug Fixes\n\n* release useDebounce and useToggle fixes ([12ad880](https://github.com/streamich/react-use/commit/12ad880))\n\n## [5.2.1](https://github.com/streamich/react-use/compare/v5.2.0...v5.2.1) (2019-01-04)\n\n\n### Bug Fixes\n\n* use function to correctly update state in useToggle ([d854d27](https://github.com/streamich/react-use/commit/d854d27))\n\n# [5.2.0](https://github.com/streamich/react-use/compare/v5.1.2...v5.2.0) (2019-01-02)\n\n\n### Features\n\n* 🎸 add useKeyPress hook ([01df885](https://github.com/streamich/react-use/commit/01df885))\n* **useKeyPress:** allow complex bindings via key combos ([e53a20f](https://github.com/streamich/react-use/commit/e53a20f))\n\n## [5.1.2](https://github.com/streamich/react-use/compare/v5.1.1...v5.1.2) (2018-12-29)\n\n\n### Bug Fixes\n\n* reset state when calling useEffect in useAsync ([2f5af2c](https://github.com/streamich/react-use/commit/2f5af2c))\n\n## [5.1.1](https://github.com/streamich/react-use/compare/v5.1.0...v5.1.1) (2018-12-20)\n\n\n### Bug Fixes\n\n* lock react and react-dom to a fixed version ([#83](https://github.com/streamich/react-use/issues/83)) ([455812d](https://github.com/streamich/react-use/commit/455812d))\n\n# [5.1.0](https://github.com/streamich/react-use/compare/v5.0.0...v5.1.0) (2018-12-19)\n\n\n### Bug Fixes\n\n* 🐛 just use any for setTimeout because of diff environments ([55673cb](https://github.com/streamich/react-use/commit/55673cb))\n* 🐛 memoized does not receive arguments ([244a533](https://github.com/streamich/react-use/commit/244a533))\n* 🐛 use Timeout type for build to work ([8c66abe](https://github.com/streamich/react-use/commit/8c66abe))\n\n\n### Features\n\n* added useDebounce ([91ff6ba](https://github.com/streamich/react-use/commit/91ff6ba))\n* pass arguments to memoized callback ([#81](https://github.com/streamich/react-use/issues/81)) ([88dd513](https://github.com/streamich/react-use/commit/88dd513))\n\n# [5.0.0](https://github.com/streamich/react-use/compare/v4.11.1...v5.0.0) (2018-12-17)\n\n\n### Features\n\n* 🎸 list all useAsync state props so that TS dont complain ([7c1b107](https://github.com/streamich/react-use/commit/7c1b107))\n* 🎸 remove experimental hooks ([533e26f](https://github.com/streamich/react-use/commit/533e26f))\n* use discriminated union in useAsync ([966af4a](https://github.com/streamich/react-use/commit/966af4a))\n\n\n### BREAKING CHANGES\n\n* useRenderProp and useAsync are removed\n\n## [4.11.1](https://github.com/streamich/react-use/compare/v4.11.0...v4.11.1) (2018-12-16)\n\n\n### Bug Fixes\n\n* synchronously re-render bug of useRaf hook ([#77](https://github.com/streamich/react-use/issues/77)) ([5d74348](https://github.com/streamich/react-use/commit/5d74348))\n\n# [4.11.0](https://github.com/streamich/react-use/compare/v4.10.0...v4.11.0) (2018-12-05)\n\n\n### Features\n\n* 🎸 add useRefMounted hook ([dfb0510](https://github.com/streamich/react-use/commit/dfb0510))\n\n# [4.10.0](https://github.com/streamich/react-use/compare/v4.9.0...v4.10.0) (2018-11-10)\n\n\n### Features\n\n* bump useWait ([124ef99](https://github.com/streamich/react-use/commit/124ef99))\n\n# [4.9.0](https://github.com/streamich/react-use/compare/v4.8.0...v4.9.0) (2018-11-06)\n\n\n### Features\n\n* add useSessionStorage hook ([eca432a](https://github.com/streamich/react-use/commit/eca432a))\n* add useWait hook ([61c6058](https://github.com/streamich/react-use/commit/61c6058))\n\n# [4.8.0](https://github.com/streamich/react-use/compare/v4.7.0...v4.8.0) (2018-11-02)\n\n\n### Features\n\n* allow useSetState setter to accept function ([bfd114a](https://github.com/streamich/react-use/commit/bfd114a))\n\n# [4.7.0](https://github.com/streamich/react-use/compare/v4.6.0...v4.7.0) (2018-10-30)\n\n\n### Features\n\n* 🎸 add useHoverDirty hook ([c2aee59](https://github.com/streamich/react-use/commit/c2aee59))\n\n# [4.6.0](https://github.com/streamich/react-use/compare/v4.5.0...v4.6.0) (2018-10-30)\n\n\n### Features\n\n* 🎸 implement useLocalStorage without events ([d211722](https://github.com/streamich/react-use/commit/d211722))\n\n# [4.5.0](https://github.com/streamich/react-use/compare/v4.4.0...v4.5.0) (2018-10-29)\n\n\n### Features\n\n* 🎸 add useAdopt hook ([91bee9a](https://github.com/streamich/react-use/commit/91bee9a))\n* 🎸 add useRenderProp hook ([2d85c61](https://github.com/streamich/react-use/commit/2d85c61))\n\n# [4.4.0](https://github.com/streamich/react-use/compare/v4.3.0...v4.4.0) (2018-10-29)\n\n\n### Features\n\n* 🎸 add useCallbag hook ([ead142c](https://github.com/streamich/react-use/commit/ead142c))\n\n# [4.3.0](https://github.com/streamich/react-use/compare/v4.2.0...v4.3.0) (2018-10-29)\n\n\n### Features\n\n* 🎸 add useOutsideClick hook ([90d2c22](https://github.com/streamich/react-use/commit/90d2c22))\n\n# [4.2.0](https://github.com/streamich/react-use/compare/v4.1.0...v4.2.0) (2018-10-29)\n\n\n### Features\n\n* 🎸 add useVideo hook ([ff05419](https://github.com/streamich/react-use/commit/ff05419))\n* 🎸 allow to pass React <video> el in useVideo and useAudio ([8670c74](https://github.com/streamich/react-use/commit/8670c74))\n\n# [4.1.0](https://github.com/streamich/react-use/compare/v4.0.0...v4.1.0) (2018-10-29)\n\n\n### Features\n\n* 🎸 add createMemo hook factory ([8730eaa](https://github.com/streamich/react-use/commit/8730eaa))\n\n# [4.0.0](https://github.com/streamich/react-use/compare/v3.1.0...v4.0.0) (2018-10-29)\n\n\n### Features\n\n* 🎸 add useNumber alias ([a58a4a7](https://github.com/streamich/react-use/commit/a58a4a7))\n* 🎸 improve useCounter interface ([395e82b](https://github.com/streamich/react-use/commit/395e82b))\n\n\n### BREAKING CHANGES\n\n* useCounter interface changed\n\n# [3.1.0](https://github.com/streamich/react-use/compare/v3.0.0...v3.1.0) (2018-10-29)\n\n\n### Features\n\n* 🎸 add useGetSetState ([dcd1013](https://github.com/streamich/react-use/commit/dcd1013))\n\n\n### Performance Improvements\n\n* ⚡️ wrape useGetSetState callbacks in useCallback ([3c1e57d](https://github.com/streamich/react-use/commit/3c1e57d))\n\n# [3.0.0](https://github.com/streamich/react-use/compare/v2.3.0...v3.0.0) (2018-10-29)\n\n\n### Features\n\n* 🎸 accept any value type in useToggle and cast it to bool ([869f767](https://github.com/streamich/react-use/commit/869f767))\n\n\n### BREAKING CHANGES\n\n* now useToggle and useBoolean accept any value type and cast it to\nboolean.\n\n# [2.3.0](https://github.com/streamich/react-use/compare/v2.2.0...v2.3.0) (2018-10-29)\n\n\n### Features\n\n* 🎸 add useBoolean hook ([ce6de24](https://github.com/streamich/react-use/commit/ce6de24))\n\n# [2.2.0](https://github.com/streamich/react-use/compare/v2.1.0...v2.2.0) (2018-10-29)\n\n\n### Features\n\n* 🎸 add useGetSet hook ([bfc30b9](https://github.com/streamich/react-use/commit/bfc30b9))\n* 🎸 add useUpdate hook ([c00f308](https://github.com/streamich/react-use/commit/c00f308))\n\n# [2.1.0](https://github.com/streamich/react-use.git/compare/v2.0.0...v2.1.0) (2018-10-28)\n\n\n### Features\n\n* 🎸 add useObservable ([711e831](https://github.com/streamich/react-use.git/commit/711e831))\n\n# [2.0.0](https://github.com/streamich/react-use.git/compare/v1.0.0...v2.0.0) (2018-10-28)\n\n\n### Features\n\n* 🎸 change API for useToggle hook ([#16](https://github.com/streamich/react-use.git/issues/16)) ([5a6da18](https://github.com/streamich/react-use.git/commit/5a6da18))\n\n\n### BREAKING CHANGES\n\n* useToggle interface changed\n\n# 1.0.0 (2018-10-28)\n\n\n### chore\n\n* 🤖 release v1 ([4236cf0](https://github.com/streamich/react-use.git/commit/4236cf0))\n\n\n### Continuous Integration\n\n* 🎡 store CircleCI artifacts, add git-cz ([690dd5e](https://github.com/streamich/react-use.git/commit/690dd5e))\n\n\n### Features\n\n* 🎸 add useAsync hook ([258d696](https://github.com/streamich/react-use.git/commit/258d696))\n* 🎸 add useAudio hook ([4336aa1](https://github.com/streamich/react-use.git/commit/4336aa1))\n* 🎸 add useBattery hook ([73ce535](https://github.com/streamich/react-use.git/commit/73ce535))\n* 🎸 add useCounter hook ([79e5b8c](https://github.com/streamich/react-use.git/commit/79e5b8c))\n* 🎸 add useCss hook ([2c0a7e4](https://github.com/streamich/react-use.git/commit/2c0a7e4))\n* 🎸 add useFavicon hook ([ab1739a](https://github.com/streamich/react-use.git/commit/ab1739a))\n* 🎸 add useGeolocation hook ([13a7326](https://github.com/streamich/react-use.git/commit/13a7326))\n* 🎸 add useHover hook ([406af20](https://github.com/streamich/react-use.git/commit/406af20))\n* 🎸 add useIdle hook ([74d3ece](https://github.com/streamich/react-use.git/commit/74d3ece))\n* 🎸 add useLifecycles hook ([f99c89f](https://github.com/streamich/react-use.git/commit/f99c89f))\n* 🎸 add useList hook ([4bea508](https://github.com/streamich/react-use.git/commit/4bea508))\n* 🎸 add useLocation hook ([46a8e2c](https://github.com/streamich/react-use.git/commit/46a8e2c))\n* 🎸 add useLogger hook ([7c38b75](https://github.com/streamich/react-use.git/commit/7c38b75))\n* 🎸 add useMap hook ([6509c25](https://github.com/streamich/react-use.git/commit/6509c25))\n* 🎸 add useMedia hook ([e1cc9ab](https://github.com/streamich/react-use.git/commit/e1cc9ab))\n* 🎸 add useMediaDevices hook ([4ea0277](https://github.com/streamich/react-use.git/commit/4ea0277))\n* 🎸 add useMotion hook ([91eb4ea](https://github.com/streamich/react-use.git/commit/91eb4ea))\n* 🎸 add useMount and useUnmount hooks ([63a1444](https://github.com/streamich/react-use.git/commit/63a1444))\n* 🎸 add useNetwork hook ([5881fa6](https://github.com/streamich/react-use.git/commit/5881fa6))\n* 🎸 add useOrientation hook ([c533b97](https://github.com/streamich/react-use.git/commit/c533b97))\n* 🎸 add useRaf hook ([26b2593](https://github.com/streamich/react-use.git/commit/26b2593))\n* 🎸 add useSetState hook ([972541d](https://github.com/streamich/react-use.git/commit/972541d))\n* 🎸 add useSize hook ([620b171](https://github.com/streamich/react-use.git/commit/620b171))\n* 🎸 add useSpeech hook ([3b971a2](https://github.com/streamich/react-use.git/commit/3b971a2))\n* 🎸 add useSprgin hook ([b4fe5b0](https://github.com/streamich/react-use.git/commit/b4fe5b0))\n* 🎸 add useTimeout hook ([86f094e](https://github.com/streamich/react-use.git/commit/86f094e))\n* 🎸 add useTitle hook ([1bff6d8](https://github.com/streamich/react-use.git/commit/1bff6d8))\n* 🎸 add useToggle() hook ([a36dceb](https://github.com/streamich/react-use.git/commit/a36dceb))\n* 🎸 add useTween hook ([877343e](https://github.com/streamich/react-use.git/commit/877343e))\n* 🎸 add useWindowSize() hook ([2c46899](https://github.com/streamich/react-use.git/commit/2c46899))\n* 🎸 do work on useLocaStorage ([2541716](https://github.com/streamich/react-use.git/commit/2541716))\n* 🎸 improve useSize, pass through state to the element ([5b1356a](https://github.com/streamich/react-use.git/commit/5b1356a))\n\n\n### BREAKING CHANGES\n\n* make semantic-release bump version\n* Released v1.0.0\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nThanks for being willing to contribute 🙌 If you contribute to this project, you agree to release your work under the license of this project.\n\n**Working on your first Pull Request?** You can learn how from this [First Contributions](https://github.com/firstcontributions/first-contributions)  guide.\n\n## Project setup\n\n1. Fork and clone the repo\n1. Run `yarn install` to install dependencies\n1. Create a branch for your PR with `git checkout -b pr/your-branch-name`\n\n> Tip: Keep your `master` branch pointing at the original repository and make\n> pull requests from branches on your fork. To do this, run:\n>\n> ```sh\n> git remote add upstream https://github.com/streamich/react-use.git\n> git fetch upstream\n> git branch --set-upstream-to=upstream/master master\n> ```\n>\n> This will add the original repository as a \"remote\" called \"upstream,\" Then\n> fetch the git information from that remote, then set your local `master`\n> branch to use the upstream master branch whenever you run `git pull`. Then you\n> can make all of your pull request branches based on this `master` branch.\n> Whenever you want to update your version of `master`, do a regular `git pull`.\n\n## Development\n\nThis library is a collection of React hooks so a proposal for a new hook will need to utilize the [React Hooks API](https://reactjs.org/docs/hooks-reference.html) internally to be taken into consideration.\n\n### Creating a new hook\n\n1. Create `src/useYourHookName.ts` and `stories/useYourHookName.story.tsx`, run `yarn start` to start the storybook development server and start coding your hook\n1. Create `tests/useYourHookName.test.ts`, run `yarn test:watch` to start the test runner in watch mode and start writing tests for your hook\n1. Create `docs/useYourHookName.md` and create documentation for your hook\n1. Export your hook from `src/index.ts` and add your hook to `README.md`\n\nYou can also write your tests first if you prefer [test-driven development](https://en.wikipedia.org/wiki/Test-driven_development).\n\n### Updating an existing hook\n\n1. Run `yarn start` to start the storybook development server and start applying changes\n2. Update tests according to your changes using `yarn test:watch`\n3. Update documentation according to your changes\n\n## Committing and Pushing changes\n\n### Commit messages\n\nThis repo uses [semantic-release](https://github.com/semantic-release/semantic-release) and [conventional commit messages](https://conventionalcommits.org) so prefix your commits with `fix:` or `feat:` if you want your changes to appear in [release notes](https://github.com/streamich/react-use/blob/master/CHANGELOG.md).\n\n### Git hooks\n\nThere are git hooks set up with this project that are automatically enabled\nwhen you install dependencies. These hooks automatically test and validate your code when creating commits. They're really handy but can be temporarily disabled by adding a `--no-verify` flag to your commit command. This is useful when you want to commit and push to get feedback on uncompleted code.\n\n## Help needed\n\nPlease have a look at the [open issues](https://github.com/streamich/react-use/issues) and respond to questions, bug reports and feature requests. Thanks!\n\nWe're also looking to improve the code coverage on this project. To easily know what hooks need tests run `yarn test:coverage` to generate a code coverage report. You can see the report in your terminal or open `coverage/lcov-report/index.html` to see the HTML report.\n"
  },
  {
    "path": "LICENSE",
    "content": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or\ndistribute this software, either in source code form or as a compiled\nbinary, for any purpose, commercial or non-commercial, and by any\nmeans.\n\nIn jurisdictions that recognize copyright laws, the author or authors\nof this software dedicate any and all copyright interest in the\nsoftware to the public domain. We make this dedication for the benefit\nof the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of\nrelinquishment in perpetuity of all present and future rights to this\nsoftware under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to <https://unlicense.org>\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n  <h1>\n    <br/>\n    <br/>\n    👍\n    <br />\n    react-use\n    <br />\n    <br />\n    <br />\n    <br />\n  </h1>\n  <sup>\n    <br />\n    <br />\n    <a href=\"https://www.npmjs.com/package/react-use\">\n       <img src=\"https://img.shields.io/npm/v/react-use.svg\" alt=\"npm package\" />\n    </a>\n    <a href=\"https://circleci.com/gh/streamich/react-use\">\n      <img src=\"https://img.shields.io/circleci/project/github/streamich/react-use/master.svg\" alt=\"CircleCI master\" />\n    </a>\n    <a href=\"https://www.npmjs.com/package/react-use\">\n      <img src=\"https://img.shields.io/npm/dm/react-use.svg\" alt=\"npm downloads\" />\n    </a>\n    <a href=\"http://streamich.github.io/react-use\">\n      <img src=\"https://img.shields.io/badge/demos-🚀-yellow.svg\" alt=\"demos\" />\n    </a>\n    <br />\n    Collection of essential <a href=\"https://reactjs.org/docs/hooks-intro.html\">React Hooks</a>.</em>\n    <em>Port of</em> <a href=\"https://github.com/streamich/libreact\"><code>libreact</code></a>.\n    <br />\n    Translations: <a href=\"https://github.com/zenghongtu/react-use-chinese/blob/master/README.md\">🇨🇳 汉语</a>\n  </sup>\n  <br />\n  <br />\n  <br />\n  <br />\n  <pre>npm i <a href=\"https://www.npmjs.com/package/react-use\">react-use</a></pre>\n  <br />\n  <br />\n  <br />\n  <br />\n  <br />\n</div>\n\n- [**Sensors**](./docs/Sensors.md)\n  - [`useBattery`](./docs/useBattery.md) &mdash; tracks device battery state. [![][img-demo]](https://codesandbox.io/s/qlvn662zww)\n  - [`useGeolocation`](./docs/useGeolocation.md) &mdash; tracks geo location state of user's device. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usegeolocation--demo)\n  - [`useHover` and `useHoverDirty`](./docs/useHover.md) &mdash; tracks mouse hover state of some element. [![][img-demo]](https://codesandbox.io/s/zpn583rvx)\n  - [`useHash`](./docs/useHash.md) &mdash; tracks location hash value. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usehash--demo)\n  - [`useIdle`](./docs/useIdle.md) &mdash; tracks whether user is being inactive.\n  - [`useIntersection`](./docs/useIntersection.md) &mdash; tracks an HTML element's intersection. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-useintersection--demo)\n  - [`useKey`](./docs/useKey.md), [`useKeyPress`](./docs/useKeyPress.md), [`useKeyboardJs`](./docs/useKeyboardJs.md), and [`useKeyPressEvent`](./docs/useKeyPressEvent.md) &mdash; track keys. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usekeypressevent--demo)\n  - [`useLocation`](./docs/useLocation.md) and [`useSearchParam`](./docs/useSearchParam.md) &mdash; tracks page navigation bar location state.\n  - [`useLongPress`](./docs/useLongPress.md) &mdash; tracks long press gesture of some element.\n  - [`useMedia`](./docs/useMedia.md) &mdash; tracks state of a CSS media query. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usemedia--demo)\n  - [`useMediaDevices`](./docs/useMediaDevices.md) &mdash; tracks state of connected hardware devices.\n  - [`useMotion`](./docs/useMotion.md) &mdash; tracks state of device's motion sensor.\n  - [`useMouse` and `useMouseHovered`](./docs/useMouse.md) &mdash; tracks state of mouse position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usemouse--docs)\n  - [`useMouseWheel`](./docs/useMouseWheel.md) &mdash; tracks deltaY of scrolled mouse wheel. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usemousewheel--docs)\n  - [`useNetworkState`](./docs/useNetworkState.md) &mdash; tracks the state of browser's network connection. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usenetworkstate--demo)\n  - [`useOrientation`](./docs/useOrientation.md) &mdash; tracks state of device's screen orientation.\n  - [`usePageLeave`](./docs/usePageLeave.md) &mdash; triggers when mouse leaves page boundaries.\n  - [`useScratch`](./docs/useScratch.md) &mdash; tracks mouse click-and-scrub state.\n  - [`useScroll`](./docs/useScroll.md) &mdash; tracks an HTML element's scroll position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usescroll--docs)\n  - [`useScrolling`](./docs/useScrolling.md) &mdash; tracks whether HTML element is scrolling.\n  - [`useStartTyping`](./docs/useStartTyping.md) &mdash; detects when user starts typing.\n  - [`useWindowScroll`](./docs/useWindowScroll.md) &mdash; tracks `Window` scroll position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usewindowscroll--docs)\n  - [`useWindowSize`](./docs/useWindowSize.md) &mdash; tracks `Window` dimensions. [![][img-demo]](https://codesandbox.io/s/m7ln22668)\n  - [`useMeasure`](./docs/useMeasure.md) and [`useSize`](./docs/useSize.md) &mdash; tracks an HTML element's dimensions. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usemeasure--demo)\n  - [`createBreakpoint`](./docs/createBreakpoint.md) &mdash; tracks `innerWidth`\n  - [`useScrollbarWidth`](./docs/useScrollbarWidth.md) &mdash; detects browser's native scrollbars width. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usescrollbarwidth--demo)\n  - [`usePinchZoom`](./docs/usePinchZoom.md) &mdash; tracks pointer events to detect pinch zoom in and out status. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usePinchZoom--demo)\n    <br/>\n    <br/>\n- [**UI**](./docs/UI.md)\n  - [`useAudio`](./docs/useAudio.md) &mdash; plays audio and exposes its controls. [![][img-demo]](https://codesandbox.io/s/2o4lo6rqy)\n  - [`useClickAway`](./docs/useClickAway.md) &mdash; triggers callback when user clicks outside target area.\n  - [`useCss`](./docs/useCss.md) &mdash; dynamically adjusts CSS.\n  - [`useDrop` and `useDropArea`](./docs/useDrop.md) &mdash; tracks file, link and copy-paste drops.\n  - [`useFullscreen`](./docs/useFullscreen.md) &mdash; display an element or video full-screen. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/ui-usefullscreen--demo)\n  - [`useSlider`](./docs/useSlider.md) &mdash; provides slide behavior over any HTML element. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/ui-useslider--demo)\n  - [`useSpeech`](./docs/useSpeech.md) &mdash; synthesizes speech from a text string. [![][img-demo]](https://codesandbox.io/s/n090mqz69m)\n  - [`useVibrate`](./docs/useVibrate.md) &mdash; provide physical feedback using the [Vibration API](https://developer.mozilla.org/en-US/docs/Web/API/Vibration_API). [![][img-demo]](https://streamich.github.io/react-use/?path=/story/ui-usevibrate--demo)\n  - [`useVideo`](./docs/useVideo.md) &mdash; plays video, tracks its state, and exposes playback controls. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/ui-usevideo--demo)\n    <br/>\n    <br/>\n- [**Animations**](./docs/Animations.md)\n  - [`useRaf`](./docs/useRaf.md) &mdash; re-renders component on each `requestAnimationFrame`.\n  - [`useInterval`](./docs/useInterval.md) and [`useHarmonicIntervalFn`](./docs/useHarmonicIntervalFn.md) &mdash; re-renders component on a set interval using `setInterval`.\n  - [`useSpring`](./docs/useSpring.md) &mdash; interpolates number over time according to spring dynamics.\n  - [`useTimeout`](./docs/useTimeout.md) &mdash; re-renders component after a timeout.\n  - [`useTimeoutFn`](./docs/useTimeoutFn.md) &mdash; calls given function after a timeout. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/animation-usetimeoutfn--demo)\n  - [`useTween`](./docs/useTween.md) &mdash; re-renders component, while tweening a number from 0 to 1. [![][img-demo]](https://codesandbox.io/s/52990wwzyl)\n  - [`useUpdate`](./docs/useUpdate.md) &mdash; returns a callback, which re-renders component when called.\n    <br/>\n    <br/>\n- [**Side-effects**](./docs/Side-effects.md)\n  - [`useAsync`](./docs/useAsync.md), [`useAsyncFn`](./docs/useAsyncFn.md), and [`useAsyncRetry`](./docs/useAsyncRetry.md) &mdash; resolves an `async` function.\n  - [`useBeforeUnload`](./docs/useBeforeUnload.md) &mdash; shows browser alert when user try to reload or close the page.\n  - [`useCookie`](./docs/useCookie.md) &mdash; provides way to read, update and delete a cookie. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-usecookie--demo)\n  - [`useCopyToClipboard`](./docs/useCopyToClipboard.md) &mdash; copies text to clipboard.\n  - [`useDebounce`](./docs/useDebounce.md) &mdash; debounces a function. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-usedebounce--demo)\n  - [`useError`](./docs/useError.md) &mdash; error dispatcher. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-useerror--demo)\n  - [`useFavicon`](./docs/useFavicon.md) &mdash; sets favicon of the page.\n  - [`useLocalStorage`](./docs/useLocalStorage.md) &mdash; manages a value in `localStorage`.\n  - [`useLockBodyScroll`](./docs/useLockBodyScroll.md) &mdash; lock scrolling of the body element.\n  - [`useRafLoop`](./docs/useRafLoop.md) &mdash; calls given function inside the RAF loop.\n  - [`useSessionStorage`](./docs/useSessionStorage.md) &mdash; manages a value in `sessionStorage`.\n  - [`useThrottle` and `useThrottleFn`](./docs/useThrottle.md) &mdash; throttles a function. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-usethrottle--demo)\n  - [`useTitle`](./docs/useTitle.md) &mdash; sets title of the page.\n  - [`usePermission`](./docs/usePermission.md) &mdash; query permission status for browser APIs.\n    <br/>\n    <br/>\n- [**Lifecycles**](./docs/Lifecycles.md)\n  - [`useEffectOnce`](./docs/useEffectOnce.md) &mdash; a modified [`useEffect`](https://reactjs.org/docs/hooks-reference.html#useeffect) hook that only runs once.\n  - [`useEvent`](./docs/useEvent.md) &mdash; subscribe to events.\n  - [`useLifecycles`](./docs/useLifecycles.md) &mdash; calls `mount` and `unmount` callbacks.\n  - [`useMountedState`](./docs/useMountedState.md) and [`useUnmountPromise`](./docs/useUnmountPromise.md) &mdash; track if component is mounted.\n  - [`usePromise`](./docs/usePromise.md) &mdash; resolves promise only while component is mounted.\n  - [`useLogger`](./docs/useLogger.md) &mdash; logs in console as component goes through life-cycles.\n  - [`useMount`](./docs/useMount.md) &mdash; calls `mount` callbacks.\n  - [`useUnmount`](./docs/useUnmount.md) &mdash; calls `unmount` callbacks.\n  - [`useUpdateEffect`](./docs/useUpdateEffect.md) &mdash; run an `effect` only on updates.\n  - [`useIsomorphicLayoutEffect`](./docs/useIsomorphicLayoutEffect.md) &mdash; `useLayoutEffect` that that works on server.\n  - [`useDeepCompareEffect`](./docs/useDeepCompareEffect.md), [`useShallowCompareEffect`](./docs/useShallowCompareEffect.md), and [`useCustomCompareEffect`](./docs/useCustomCompareEffect.md)\n    <br/>\n    <br/>\n- [**State**](./docs/State.md)\n  - [`createMemo`](./docs/createMemo.md) &mdash; factory of memoized hooks.\n  - [`createReducer`](./docs/createReducer.md) &mdash; factory of reducer hooks with custom middleware.\n  - [`createReducerContext`](./docs/createReducerContext.md) and [`createStateContext`](./docs/createStateContext.md) &mdash; factory of hooks for a sharing state between components.\n  - [`useDefault`](./docs/useDefault.md) &mdash; returns the default value when state is `null` or `undefined`.\n  - [`useGetSet`](./docs/useGetSet.md) &mdash; returns state getter `get()` instead of raw state.\n  - [`useGetSetState`](./docs/useGetSetState.md) &mdash; as if [`useGetSet`](./docs/useGetSet.md) and [`useSetState`](./docs/useSetState.md) had a baby.\n  - [`useLatest`](./docs/useLatest.md) &mdash; returns the latest state or props\n  - [`usePrevious`](./docs/usePrevious.md) &mdash; returns the previous state or props. [![][img-demo]](https://codesandbox.io/s/fervent-galileo-krgx6)\n  - [`usePreviousDistinct`](./docs/usePreviousDistinct.md) &mdash; like `usePrevious` but with a predicate to determine if `previous` should update.\n  - [`useObservable`](./docs/useObservable.md) &mdash; tracks latest value of an `Observable`.\n  - [`useRafState`](./docs/useRafState.md) &mdash; creates `setState` method which only updates after `requestAnimationFrame`. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-userafstate--demo)\n  - [`useSetState`](./docs/useSetState.md) &mdash; creates `setState` method which works like `this.setState`. [![][img-demo]](https://codesandbox.io/s/n75zqn1xp0)\n  - [`useStateList`](./docs/useStateList.md) &mdash; circularly iterates over an array. [![][img-demo]](https://codesandbox.io/s/bold-dewdney-pjzkd)\n  - [`useToggle` and `useBoolean`](./docs/useToggle.md) &mdash; tracks state of a boolean. [![][img-demo]](https://codesandbox.io/s/focused-sammet-brw2d)\n  - [`useCounter` and `useNumber`](./docs/useCounter.md) &mdash; tracks state of a number. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usecounter--demo)\n  - [`useList`](./docs/useList.md) ~and [`useUpsert`](./docs/useUpsert.md)~ &mdash; tracks state of an array. [![][img-demo]](https://codesandbox.io/s/wonderful-mahavira-1sm0w)\n  - [`useMap`](./docs/useMap.md) &mdash; tracks state of an object. [![][img-demo]](https://codesandbox.io/s/quirky-dewdney-gi161)\n  - [`useSet`](./docs/useSet.md) &mdash; tracks state of a Set. [![][img-demo]](https://codesandbox.io/s/bold-shtern-6jlgw)\n  - [`useQueue`](./docs/useQueue.md) &mdash; implements simple queue.\n  - [`useStateValidator`](./docs/useStateValidator.md) &mdash; tracks state of an object. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usestatevalidator--demo)\n  - [`useStateWithHistory`](./docs/useStateWithHistory.md) &mdash; stores previous state values and provides handles to travel through them. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usestatewithhistory--demo)\n  - [`useMultiStateValidator`](./docs/useMultiStateValidator.md) &mdash; alike the `useStateValidator`, but tracks multiple states at a time. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usemultistatevalidator--demo)\n  - [`useMediatedState`](./docs/useMediatedState.md) &mdash; like the regular `useState` but with mediation by custom function. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usemediatedstate--demo)\n  - [`useFirstMountState`](./docs/useFirstMountState.md) &mdash; check if current render is first. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usefirstmountstate--demo)\n  - [`useRendersCount`](./docs/useRendersCount.md) &mdash; count component renders. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-userenderscount--demo)\n  - [`createGlobalState`](./docs/createGlobalState.md) &mdash; cross component shared state.[![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-createglobalstate--demo)\n  - [`useMethods`](./docs/useMethods.md) &mdash; neat alternative to `useReducer`. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usemethods--demo)\n    <br/>\n    <br/>\n- [**Miscellaneous**]()\n  - [`useEnsuredForwardedRef`](./docs/useEnsuredForwardedRef.md) and [`ensuredForwardRef`](./docs/useEnsuredForwardedRef.md) &mdash; use a React.forwardedRef safely. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-useensuredforwardedref--demo)\n\n<br />\n<br />\n<br />\n<br />\n<br />\n<br />\n<br />\n\n<p align=\"center\">\n  <a href=\"./docs/Usage.md\"><strong>Usage</strong></a> &mdash; how to import.\n  <br />\n  <a href=\"./LICENSE\"><strong>Unlicense</strong></a> &mdash; public domain.\n  <br />\n  <a href=\"https://opencollective.com/react-use/contribute\"><strong>Support</strong></a> &mdash; add yourself to backer list below.\n</p>\n\n<br />\n<br />\n<br />\n<br />\n<br />\n\n[img-demo]: https://img.shields.io/badge/demo-%20%20%20%F0%9F%9A%80-green.svg\n\n<div align=\"center\">\n  <h1>Contributors</h1>\n</div>\n\n<br />\n<br />\n\n<a href=\"https://github.com/streamich/react-use/graphs/contributors\"><img src=\"https://opencollective.com/react-use/contributors.svg?width=890&button=false\" /></a>\n\n<br />\n<br />\n<br />\n<br />\n<br />\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nWe release patches for security vulnerabilities. The latest major version\nwill support security patches.\n\n## Reporting a Vulnerability\n\nPlease report (suspected) security vulnerabilities to\n**[streamich@gmail.com](mailto:streamich@gmail.com)**. We will try to respond\nwithin 48 hours. If the issue is confirmed, we will release a patch as soon\nas possible depending on complexity.\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = {\n  presets: [\n    [\n      \"@babel/preset-env\",\n      {\n        targets: {\n          node: \"current\"\n        }\n      }\n    ],\n    \"@babel/preset-react\",\n    \"@babel/preset-typescript\"\n  ],\n  env: {\n    test: {\n      plugins: ['dynamic-import-node']\n    },\n    production: {\n      plugins: ['@babel/plugin-syntax-dynamic-import']\n    }\n  }\n};\n"
  },
  {
    "path": "docs/Animations.md",
    "content": "# Animations\n\n*\"Animation Hooks\"* usually interpolate numeric values over time.\n"
  },
  {
    "path": "docs/Lifecycles.md",
    "content": "# Lifecycle\n\n*\"Lifecycle Hooks\"* modify and extend built-in React hooks or imitate React Class component lifecycle patterns.\n"
  },
  {
    "path": "docs/Sensors.md",
    "content": "# Sensors\n\n*\"Sensor Hooks\"* listen to changes in some interface and force your components\nto be re-rendered with the new state, up-to-date state.\n"
  },
  {
    "path": "docs/Side-effects.md",
    "content": "# Side-effects\n\n*\"Side-effect Hooks\"* allow your app trigger various side-effects using browser's API.\n"
  },
  {
    "path": "docs/State.md",
    "content": "# State\n\n*\"State Hooks\"* allow you to easily manage state of booleans, arrays, and maps."
  },
  {
    "path": "docs/UI.md",
    "content": "# UI\n\n*\"UI Hooks\"* allow you to control and subscribe to state changes of UI elements.\n"
  },
  {
    "path": "docs/Usage.md",
    "content": "# Usage\n\nYou need to have React [`16.8.0`](https://reactjs.org/blog/2019/02/06/react-v16.8.0.html) or later installed to use the Hooks API. You can import each hook individually\n\n```js\nimport useToggle from 'react-use/lib/useToggle'\n```\n\nor use ES6 named imports (tree shaking recommended)\n\n```js\nimport {useToggle} from 'react-use'\n```\n\nDepending on your bundler you might run into a missing dependency error with ES6 named import statements. Some hooks require you to install peer dependencies so we recommend using individual imports. If you want the best of both worlds you can transform the named import statements to individual import statements with [`babel-plugin-import`](https://github.com/ant-design/babel-plugin-import) by adding the following config to your `.babelrc` file:\n\n```json\n[\n      'import',\n      {\n        libraryName: 'react-use',\n        camel2DashComponentName: false,\n        customName(/** @type {string} */ name) {\n          const libraryDirectory = name.startsWith('Use')\n            ? 'lib/component'\n            : name.startsWith('create')\n            ? 'lib/factory'\n            : 'lib'\n          return `react-use/${libraryDirectory}/${name}`\n        }\n      },\n      'import-react-use'\n    ]\n```\n"
  },
  {
    "path": "docs/createBreakpoint.md",
    "content": "# `createBreakpoint`\n\n## Usage\n\n### use default breakpoint\n\nlaptopL: 1440, laptop: 1024, tablet: 768\n\n```jsx\nimport React from \"react\";\nimport { createBreakpoint } from \"react-use\";\n\nconst useBreakpoint = createBreakpoint();\n\nconst Demo = () => {\n  const breakpoint = useBreakpoint();\n\n  if (breakpoint === \"laptopL\") return <div> This is very big Laptop </div>;\n  else if (breakpoint == \"laptop\") return <div> This is Laptop</div>;\n  else if (breakpoint == \"tablet\") return <div> This is Tablet</div>;\n  else return <div> Too small!</div>;\n};\n```\n\n### use custom breakpoint\n\nXL: 1280, L: 768, S: 350\n\n```jsx\nimport React from \"react\";\nimport { createBreakpoint } from \"react-use\";\n\nconst useBreakpoint = createBreakpoint({ XL: 1280, L: 768, S: 350 });\n\nconst Demo = () => {\n  const breakpoint = useBreakpoint();\n\n  if (breakpoint === \"XL\") return <div> XL </div>;\n  else if (breakpoint == \"L\") return <div> LoL</div>;\n  else if (breakpoint == \"S\") return <div> Sexyy</div>;\n  else return <div> Wth</div>;\n};\n```\n"
  },
  {
    "path": "docs/createGlobalState.md",
    "content": "# `useGlobalState`\n\nA React hook that creates a globally shared state.\n\n## Usage\n\n```tsx\nconst useGlobalValue = createGlobalState<number>(0);\n\nconst CompA: FC = () => {\n  const [value, setValue] = useGlobalValue();\n\n  return <button onClick={() => setValue(value + 1)}>+</button>;\n};\n\nconst CompB: FC = () => {\n  const [value, setValue] = useGlobalValue();\n\n  return <button onClick={() => setValue(value - 1)}>-</button>;\n};\n\nconst Demo: FC = () => {\n  const [value] = useGlobalValue();\n  return (\n    <div>\n      <p>{value}</p>\n      <CompA />\n      <CompB />\n    </div>\n  );\n};\n```\n\nIt also allows initializing the state with a function and using a function in the setState:\n\n```tsx\nconst useGlobalValue = createGlobalState<number>(() => 0);\n\nconst CompA: FC = () => {\n  const [value, setValue] = useGlobalValue();\n\n  return <button onClick={() => setValue(value => value + 1)}>+</button>;\n};\n\nconst CompB: FC = () => {\n  const [value, setValue] = useGlobalValue();\n\n  return <button onClick={() => setValue(value => value - 1)}>-</button>;\n};\n\nconst Demo: FC = () => {\n  const [value] = useGlobalValue();\n  return (\n    <div>\n      <p>{value}</p>\n      <CompA />\n      <CompB />\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/createMemo.md",
    "content": "# `createMemo`\n\nHook factory, receives a function to be memoized, returns a memoized React hook,\nwhich receives the same arguments and returns the same result as the original function.\n\n\n## Usage\n\n```jsx\nimport {createMemo} from 'react-use';\n\nconst fibonacci = n => {\n  if (n === 0) return 0;\n  if (n === 1) return 1;\n  return fibonacci(n - 1) + fibonacci(n - 2);\n};\n\nconst useMemoFibonacci = createMemo(fibonacci);\n\nconst Demo = () => {\n  const result = useMemoFibonacci(10);\n\n  return (\n    <div>\n      fib(10) = {result}\n    </div>\n  );\n};\n```\n\n\n## Reference\n\n```js\nconst useMemoFn = createMemo(fn);\n```\n"
  },
  {
    "path": "docs/createReducer.md",
    "content": "# `createReducer`\n\nFactory for reducer hooks with custom middleware with an identical API as [React's `useReducer`](https://reactjs.org/docs/hooks-reference.html#usereducer). Compatible with [Redux middleware](https://redux.js.org/advanced/middleware).\n\n## Usage\n\nAn example with [`redux-thunk`](https://github.com/reduxjs/redux-thunk) and [`redux-logger`](https://github.com/LogRocket/redux-logger).\n\n```jsx\nimport { createReducer } from 'react-use';\nimport logger from 'redux-logger';\nimport thunk from 'redux-thunk';\n\nconst useThunkReducer = createReducer(thunk, logger);\n\nfunction reducer(state, action) {\n  switch (action.type) {\n    case 'increment':\n      return { count: state.count + 1 };\n    case 'decrement':\n      return { count: state.count - 1 };\n    case 'reset':\n      return { count: action.payload };\n    default:\n      throw new Error();\n  }\n}\n\nconst Demo = ({ initialCount = 1 }) => {\n  // Action creator to increment count, wait a second and then reset\n  const addAndReset = React.useCallback(() => {\n    return dispatch => {\n      dispatch({ type: 'increment' });\n\n      setTimeout(() => {\n        dispatch({ type: 'reset', payload: initialCount });\n      }, 1000);\n    };\n  }, [initialCount]);\n\n  const [state, dispatch] = useThunkReducer(reducer, initialCount);\n\n  return (\n    <div>\n      <p>count: {state.count}</p>\n      <button onClick={() => dispatch(addAndReset())}>Add and reset</button>\n      <button\n        onClick={() => dispatch({ type: 'reset', payload: { count: initialCount }})}\n      >\n        Reset\n      </button>\n      <button onClick={() => dispatch({ type: 'increment' })}>+</button>\n      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```js\nconst useMiddlewareReducer = createReducer(...middlewares);\n```\n"
  },
  {
    "path": "docs/createReducerContext.md",
    "content": "# `createReducerContext`\n\nFactory for react context hooks that will behave just like [React's `useReducer`](https://reactjs.org/docs/hooks-reference.html#usereducer) except the state will be shared among all components in the provider.\n\nThis allows you to have a shared state that any component can update easily.\n\n## Usage\n\nAn example with two counters that shared the same value.\n\n```jsx\nimport { createReducerContext } from 'react-use';\n\ntype Action = 'increment' | 'decrement';\n\nconst reducer = (state: number, action: Action) => {\n  switch (action) {\n    case 'increment':\n      return state + 1;\n    case 'decrement':\n      return state - 1;\n    default:\n      throw new Error();\n  }\n};\n\nconst [useSharedCounter, SharedCounterProvider] = createReducerContext(reducer, 0);\n\nconst ComponentA = () => {\n  const [count, dispatch] = useSharedCounter();\n  return (\n    <p>\n      Component A &nbsp;\n      <button type=\"button\" onClick={() => dispatch('decrement')}>\n        -\n      </button>\n      &nbsp;{count}&nbsp;\n      <button type=\"button\" onClick={() => dispatch('increment')}>\n        +\n      </button>\n    </p>\n  );\n};\n\nconst ComponentB = () => {\n  const [count, dispatch] = useSharedCounter();\n  return (\n    <p>\n      Component B &nbsp;\n      <button type=\"button\" onClick={() => dispatch('decrement')}>\n        -\n      </button>\n      &nbsp;{count}&nbsp;\n      <button type=\"button\" onClick={() => dispatch('increment')}>\n        +\n      </button>\n    </p>\n  );\n};\n\nconst Demo = () => {\n  return (\n    <SharedCounterProvider>\n      <p>Those two counters share the same value.</p>\n      <ComponentA />\n      <ComponentB />\n    </SharedCounterProvider>\n  );\n};\n```\n\n## Reference\n\n```jsx\nconst [useSharedState, SharedStateProvider] = createReducerContext(reducer, initialState);\n\n// In wrapper\nconst Wrapper = ({ children }) => (\n  // You can override the initial state for each Provider\n  <SharedStateProvider initialState={overrideInitialState}>\n    { children }\n  </SharedStateProvider>\n)\n\n// In a component\nconst Component = () => {\n  const [sharedState, dispatch] = useSharedState();\n\n  // ...\n}\n```\n"
  },
  {
    "path": "docs/createStateContext.md",
    "content": "# `createStateContext`\n\nFactory for react context hooks that will behave just like [React's `useState`](https://reactjs.org/docs/hooks-reference.html#usestate) except the state will be shared among all components in the provider.\n\nThis allows you to have a shared state that any component can update easily.\n\n## Usage\n\nAn example with a shared text between two input fields.\n\n```jsx\nimport { createStateContext } from 'react-use';\n\nconst [useSharedText, SharedTextProvider] = createStateContext('');\n\nconst ComponentA = () => {\n  const [text, setText] = useSharedText();\n  return (\n    <p>\n      Component A:\n      <br />\n      <input type=\"text\" value={text} onInput={ev => setText(ev.target.value)} />\n    </p>\n  );\n};\n\nconst ComponentB = () => {\n  const [text, setText] = useSharedText();\n  return (\n    <p>\n      Component B:\n      <br />\n      <input type=\"text\" value={text} onInput={ev => setText(ev.target.value)} />\n    </p>\n  );\n};\n\nconst Demo = () => {\n  return (\n    <SharedTextProvider>\n      <p>Those two fields share the same value.</p>\n      <ComponentA />\n      <ComponentB />\n    </SharedTextProvider>\n  );\n};\n```\n\n## Reference\n\n```jsx\nconst [useSharedState, SharedStateProvider] = createStateContext(initialValue);\n\n// In wrapper\nconst Wrapper = ({ children }) => (\n  // You can override the initial value for each Provider\n  <SharedStateProvider initialValue={overrideInitialValue}>\n    { children }\n  </SharedStateProvider>\n)\n\n// In a component\nconst Component = () => {\n  const [sharedState, setSharedState] = useSharedState();\n\n  // ...\n}\n```\n"
  },
  {
    "path": "docs/useAsync.md",
    "content": "# `useAsync`\n\nReact hook that resolves an `async` function or a function that returns\na promise;\n\n## Usage\n\n```jsx\nimport {useAsync} from 'react-use';\n\nconst Demo = ({url}) => {\n  const state = useAsync(async () => {\n    const response = await fetch(url);\n    const result = await response.text();\n    return result\n  }, [url]);\n\n  return (\n    <div>\n      {state.loading\n        ? <div>Loading...</div>\n        : state.error\n          ? <div>Error: {state.error.message}</div>\n          : <div>Value: {state.value}</div>\n      }\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseAsync(fn, args?: any[]);\n```\n"
  },
  {
    "path": "docs/useAsyncFn.md",
    "content": "# `useAsyncFn`\n\nReact hook that returns state and a callback for an `async` function or a\nfunction that returns a promise. The state is of the same shape as `useAsync`.\n\n## Usage\n\n```jsx\nimport {useAsyncFn} from 'react-use';\n\nconst Demo = ({url}) => {\n  const [state, doFetch] = useAsyncFn(async () => {\n    const response = await fetch(url);\n    const result = await response.text();\n    return result\n  }, [url]);\n\n  return (\n    <div>\n      {state.loading\n        ? <div>Loading...</div>\n        : state.error\n          ? <div>Error: {state.error.message}</div>\n          : <div>Value: {state.value}</div>\n      }\n      <button onClick={() => doFetch()}>Start loading</button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseAsyncFn<Result, Args>(fn, deps?: any[], initialState?: AsyncState<Result>);\n```\n"
  },
  {
    "path": "docs/useAsyncRetry.md",
    "content": "# `useAsyncRetry`\n\nUses `useAsync` with an additional `retry` method to easily retry/refresh the async function;\n\n## Usage\n\n```jsx\nimport {useAsyncRetry} from 'react-use';\n\nconst Demo = ({url}) => {\n  const state = useAsyncRetry(async () => {\n    const response = await fetch(url);\n    const result = await response.text();\n    return result;\n  }, [url]);\n\n  return (\n    <div>\n      {state.loading\n        ? <div>Loading...</div>\n        : state.error\n          ? <div>Error: {state.error.message}</div>\n          : <div>Value: {state.value}</div>\n      }\n      {!loading && <button onClick={() => state.retry()}>Start loading</button>}\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseAsyncRetry(fn, args?: any[]);\n```\n"
  },
  {
    "path": "docs/useAudio.md",
    "content": "# `useAudio`\n\nCreates `<audio>` element, tracks its state and exposes playback controls.\n\n\n## Usage\n\n```jsx\nimport {useAudio} from 'react-use';\n\nconst Demo = () => {\n  const [audio, state, controls, ref] = useAudio({\n    src: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3',\n    autoPlay: true,\n  });\n\n  return (\n    <div>\n      {audio}\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      <button onClick={controls.pause}>Pause</button>\n      <button onClick={controls.play}>Play</button>\n      <br/>\n      <button onClick={controls.mute}>Mute</button>\n      <button onClick={controls.unmute}>Un-mute</button>\n      <br/>\n      <button onClick={() => controls.volume(.1)}>Volume: 10%</button>\n      <button onClick={() => controls.volume(.5)}>Volume: 50%</button>\n      <button onClick={() => controls.volume(1)}>Volume: 100%</button>\n      <br/>\n      <button onClick={() => controls.seek(state.time - 5)}>-5 sec</button>\n      <button onClick={() => controls.seek(state.time + 5)}>+5 sec</button>\n    </div>\n  );\n};\n```\n\n\n## Reference\n\n```jsx\nconst [audio, state, controls, ref] = useAudio(props);\nconst [audio, state, controls] = useAudio(<audio {...props}/>);\n```\n\n`audio` is React's `<audio>` element that you have to insert somewhere in your\nrender tree, for example:\n\n```jsx\n<div>{audio}</div>\n```\n\n`state` tracks the state of the audio and has the following shape:\n\n```json\n{\n  \"buffered\": [\n    {\n      \"start\": 0,\n      \"end\": 425.952625\n    }\n  ],\n  \"time\": 5.244996,\n  \"duration\": 425.952625,\n  \"paused\": false,\n  \"muted\": false,\n  \"volume\": 1,\n  \"playing\": true\n}\n```\n\n`playing`: The audio is being played and is affected by the network. If it starts to buffer audio, it will be false\n\n`controls` is a list collection of methods that allow you to control the\nplayback of the audio, it has the following interface:\n\n```ts\ninterface AudioControls {\n  play: () => Promise<void> | void;\n  pause: () => void;\n  mute: () => void;\n  unmute: () => void;\n  volume: (volume: number) => void;\n  seek: (time: number) => void;\n}\n```\n\n`ref` is a React reference to HTML `<audio>` element, you can access the element by\n`ref.current`, note that it may be `null`.\n\nAnd finally, `props` &mdash; all props that `<audio>` accepts.\n"
  },
  {
    "path": "docs/useBattery.md",
    "content": "# `useBattery`\n\nReact sensor hook that tracks battery status.\n\n>**Note:** current `BatteryManager` API state is obsolete.  \n>Although it may still work in some browsers, its use is discouraged since it could be removed at any time.\n\n\n## Usage\n\n```jsx\nimport {useBattery} from 'react-use';\n\nconst Demo = () => {\n  const batteryState = useBattery();\n\n  if (!batteryState.isSupported) {\n    return (\n      <div>\n        <strong>Battery sensor</strong>: <span>not supported</span>\n      </div>\n    );\n  }\n\n  if (!batteryState.fetched) {\n    return (\n      <div>\n        <strong>Battery sensor</strong>: <span>supported</span> <br />\n        <strong>Battery state</strong>: <span>fetching</span>\n      </div>\n    );\n  }\n\n  return (\n    <div>\n      <strong>Battery sensor</strong>:&nbsp;&nbsp; <span>supported</span> <br />\n      <strong>Battery state</strong>: <span>fetched</span> <br />\n      <strong>Charge level</strong>:&nbsp;&nbsp; <span>{ (batteryState.level * 100).toFixed(0) }%</span> <br />\n      <strong>Charging</strong>:&nbsp;&nbsp; <span>{ batteryState.charging ? 'yes' : 'no' }</span> <br />\n      <strong>Charging time</strong>:&nbsp;&nbsp;\n      <span>{ batteryState.chargingTime ? batteryState.chargingTime : 'finished' }</span> <br />\n      <strong>Discharging time</strong>:&nbsp;&nbsp; <span>{ batteryState.dischargingTime }</span>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nconst {isSupported, level, charging, dischargingTime, chargingTime} = useBattery();\n```\n- **`isSupported`**_`: boolean`_ - whether browser/devise supports BatteryManager;\n- **`fetched`**_`: boolean`_ - whether battery state is fetched;\n- **`level`**_`: number`_ - representing the system's battery charge level scaled to a value between 0.0 and 1.0.\n- **`charging`**_`: boolean`_ - indicating whether or not the battery is currently being charged.\n- **`dischargingTime`**_`: number`_ - remaining time in seconds until the battery is completely discharged and the system will suspend.\n- **`chargingTime`**_`: number`_ - remaining time in seconds until the battery is fully charged, or 0 if the battery is already fully charged.\n"
  },
  {
    "path": "docs/useBeforeUnload.md",
    "content": "# `useBeforeUnload`\n\nReact side-effect hook that shows browser alert when user try to reload or close the page.\n\n\n## Usage\n\n### Boolean check\n\n```jsx\nimport {useBeforeUnload} from 'react-use';\n\nconst Demo = () => {\n  const [dirty, toggleDirty] = useToggle(false);\n  useBeforeUnload(dirty, 'You have unsaved changes, are you sure?');\n\n  return (\n    <div>\n      {dirty && <p>Try to reload or close tab</p>}\n      <button onClick={() => toggleDirty()}>{dirty ? 'Disable' : 'Enable'}</button>\n    </div>\n  );\n};\n```\n\n### Function check\n\nNote: Since every `dirtyFn` change registers a new callback, you should use\n[refs](https://reactjs.org/docs/hooks-faq.html#how-to-read-an-often-changing-value-from-usecallback)\nif your test value changes often.\n\n```jsx\nimport {useBeforeUnload} from 'react-use';\n\nconst Demo = () => {\n  const [dirty, toggleDirty] = useToggle(false);\n  const dirtyFn = useCallback(() => {\n    return dirty;\n  }, [dirty]);\n  useBeforeUnload(dirtyFn, 'You have unsaved changes, are you sure?');\n\n  return (\n    <div>\n      {dirty && <p>Try to reload or close tab</p>}\n      <button onClick={() => toggleDirty()}>{dirty ? 'Disable' : 'Enable'}</button>\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useClickAway.md",
    "content": "# `useClickAway`\n\nReact UI hook that triggers a callback when user\nclicks outside the target element.\n\n\n## Usage\n\n```jsx\nimport {useClickAway} from 'react-use';\n\nconst Demo = () => {\n  const ref = useRef(null);\n  useClickAway(ref, () => {\n    console.log('OUTSIDE CLICKED');\n  });\n\n  return (\n    <div ref={ref} style={{\n      width: 200,\n      height: 200,\n      background: 'red',\n    }} />\n  );\n};\n```\n\n## Reference\n\n```js\nuseClickAway(ref, onMouseEvent)\nuseClickAway(ref, onMouseEvent, ['click'])\nuseClickAway(ref, onMouseEvent, ['mousedown', 'touchstart'])\n```\n"
  },
  {
    "path": "docs/useCookie.md",
    "content": "# `useCookie`\n\nReact hook that returns the current value of a `cookie`, a callback to update the `cookie`\nand a callback to delete the `cookie.`\n\n## Usage\n\n```jsx\nimport { useCookie } from \"react-use\";\n\nconst Demo = () => {\n  const [value, updateCookie, deleteCookie] = useCookie(\"my-cookie\");\n  const [counter, setCounter] = useState(1);\n\n  useEffect(() => {\n    deleteCookie();\n  }, []);\n\n  const updateCookieHandler = () => {\n    updateCookie(`my-awesome-cookie-${counter}`);\n    setCounter(c => c + 1);\n  };\n\n  return (\n    <div>\n      <p>Value: {value}</p>\n      <button onClick={updateCookieHandler}>Update Cookie</button>\n      <br />\n      <button onClick={deleteCookie}>Delete Cookie</button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nconst [value, updateCookie, deleteCookie] = useCookie(cookieName: string);\n```\n"
  },
  {
    "path": "docs/useCopyToClipboard.md",
    "content": "# `useCopyToClipboard`\n\nCopy text to a user's clipboard.\n\n## Usage\n\n```jsx\nconst Demo = () => {\n  const [text, setText] = React.useState('');\n  const [state, copyToClipboard] = useCopyToClipboard();\n\n  return (\n    <div>\n      <input value={text} onChange={e => setText(e.target.value)} />\n      <button type=\"button\" onClick={() => copyToClipboard(text)}>copy text</button>\n      {state.error\n        ? <p>Unable to copy value: {state.error.message}</p>\n        : state.value && <p>Copied {state.value}</p>}\n    </div>\n  )\n}\n```\n\n## Reference\n\n```js\nconst [{value, error, noUserInteraction}, copyToClipboard] = useCopyToClipboard();\n```\n\n- `value` &mdash; value that was copied to clipboard, undefined when nothing was copied.\n- `error` &mdash; caught error when trying to copy to clipboard.\n- `noUserInteraction` &mdash; boolean indicating if user interaction was required to copy the value to clipboard to expose full API from underlying [`copy-to-clipboard`](https://github.com/sudodoki/copy-to-clipboard) library.\n"
  },
  {
    "path": "docs/useCounter.md",
    "content": "# `useCounter`\n\nReact state hook that tracks a numeric value.\n\n`useNumber` is an alias for `useCounter`.\n\n\n## Usage\n\n```jsx\nimport {useCounter, useNumber} from 'react-use';\n\nconst Demo = () => {\n  const [min, { inc: incMin, dec: decMin }] = useCounter(1);\n  const [max, { inc: incMax, dec: decMax }] = useCounter(10);\n  const [value, { inc, dec, set, reset }] = useCounter(5, max, min);\n\n  return (\n    <div>\n      <div>\n        current: { value } [min: { min }; max: { max }]\n      </div>\n\n      <br />\n      Current value: <button onClick={ () => inc() }>Increment</button>\n      <button onClick={ () => dec() }>Decrement</button>\n      <button onClick={ () => inc(5) }>Increment (+5)</button>\n      <button onClick={ () => dec(5) }>Decrement (-5)</button>\n      <button onClick={ () => set(100) }>Set 100</button>\n      <button onClick={ () => reset() }>Reset</button>\n      <button onClick={ () => reset(25) }>Reset (25)</button>\n\n      <br />\n      <br />\n      Min value:\n      <button onClick={ () => incMin() }>Increment</button>\n      <button onClick={ () => decMin() }>Decrement</button>\n\n      <br />\n      <br />\n      Max value:\n      <button onClick={ () => incMax() }>Increment</button>\n      <button onClick={ () => decMax() }>Decrement</button>\n    </div>\n  );\n};\n```\n\n\n## Reference\n\n```ts \nconst [ current, { inc, dec, get, set, reset } ] = useCounter(initial: number, max: number | null = null, min: number | null = null);\n```\n- `current` - current counter value;\n- `get(): number` - getter of current counter value;\n- `inc(delta: number): void` - increment current value;\n- `dec(delta: number): void` - decrement current value;\n- `set(value: number): void` - set arbitrary value;\n- `reset(value: number): void` - as the `set`, but also will assign value by reference to the `initial` parameter;\n"
  },
  {
    "path": "docs/useCss.md",
    "content": "# `useCss`\n\nReact UI hook that changes [CSS dynamically][gen-5]. Works like \"virtual CSS\" &mdash;\nit re-renders only CSS rules that change. It is different from inline styles, because\nyou can use media queries and pseudo selectors.\n\n\n## Usage\n\n```jsx\nimport {useCss} from 'react-use';\n\nconst Demo = () => {\n  const className = useCss({\n    color: 'red',\n    border: '1px solid red',\n    '&:hover': {\n      color: 'blue',\n    },\n  });\n\n  return (\n    <div className={className}>\n      Hover me!\n    </div>\n  );\n};\n```\n\n\n## Examples\n\n```js\nconst className = useCss({\n  color: 'tomato',\n  '&:hover': {\n    color: 'orange',\n  },\n});\n\nconst className = useCss({\n  svg: {\n    fill: 'tomato',\n  },\n  '.global_class &:hover svg': {\n    fill: 'orange',\n  },\n});\n\nconst className = useCss({\n  color: 'tomato',\n  '@media only screen and (max-width: 600px)': {\n    color: 'orange',\n    '&:hover': {\n      color: 'red',\n    }\n  },\n});\n```\n\n[gen-5]: https://github.com/streamich/freestyler/blob/master/docs/en/generations.md#5th-generation\n"
  },
  {
    "path": "docs/useCustomCompareEffect.md",
    "content": "# `useCustomCompareEffect`\n\nA modified useEffect hook that accepts a comparator which is used for comparison on dependencies instead of reference equality.\n\n## Usage\n\n```jsx\nimport {useCounter, useCustomCompareEffect} from 'react-use';\nimport isEqual from 'lodash/isEqual';\n\nconst Demo = () => {\n  const [count, {inc: inc}] = useCounter(0);\n  const options = { step: 2 };\n\n  useCustomCompareEffect(() => {\n    inc(options.step)\n  }, [options], (prevDeps, nextDeps) => isEqual(prevDeps, nextDeps));\n\n  return (\n    <div>\n      <p>useCustomCompareEffect with deep comparison: {count}</p>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseCustomCompareEffect(effect: () => void | (() => void | undefined), deps: any[], depsEqual: (prevDeps: any[], nextDeps: any[]) => boolean);\n```\n"
  },
  {
    "path": "docs/useDebounce.md",
    "content": "# `useDebounce`\n\nReact hook that delays invoking a function until after wait milliseconds have elapsed since the last time the debounced function was invoked.\n\nThe third argument is the array of values that the debounce depends on, in the same manner as useEffect. The debounce timeout will start when one of the values changes.\n\n## Usage\n\n```jsx\nconst Demo = () => {\n  const [state, setState] = React.useState('Typing stopped');\n  const [val, setVal] = React.useState('');\n  const [debouncedValue, setDebouncedValue] = React.useState('');\n\n  const [, cancel] = useDebounce(\n    () => {\n      setState('Typing stopped');\n      setDebouncedValue(val);\n    },\n    2000,\n    [val]\n  );\n\n  return (\n    <div>\n      <input\n        type=\"text\"\n        value={val}\n        placeholder=\"Debounced input\"\n        onChange={({ currentTarget }) => {\n          setState('Waiting for typing to stop...');\n          setVal(currentTarget.value);\n        }}\n      />\n      <div>{state}</div>\n      <div>\n        Debounced value: {debouncedValue}\n        <button onClick={cancel}>Cancel debounce</button>\n      </div>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nconst [\n    isReady: () => boolean | null,\n    cancel: () => void,\n] = useDebounce(fn: Function, ms: number, deps: DependencyList = []);\n```\n\n- **`fn`**_`: Function`_ - function that will be called;\n- **`ms`**_`: number`_ - delay in milliseconds;\n- **`deps`**_`: DependencyList`_ - array of values that the debounce depends on, in the same manner as useEffect;\n- **`isReady`**_`: ()=>boolean|null`_ - function returning current debounce state:\n    - `false` - pending\n    - `true` - called\n    - `null` - cancelled\n- **`cancel`**_`: ()=>void`_ - cancel the debounce\n"
  },
  {
    "path": "docs/useDeepCompareEffect.md",
    "content": "# `useDeepCompareEffect`\n\nA modified useEffect hook that is using deep comparison on its dependencies instead of reference equality.\n\n## Usage\n\n```jsx\nimport {useCounter, useDeepCompareEffect} from 'react-use';\n\nconst Demo = () => {\n  const [count, {inc: inc}] = useCounter(0);\n  const options = { step: 2 };\n\n  useDeepCompareEffect(() => {\n    inc(options.step)\n  }, [options]);\n\n  return (\n    <div>\n      <p>useDeepCompareEffect: {count}</p>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseDeepCompareEffect(effect: () => void | (() => void | undefined), deps: any[]);\n```\n"
  },
  {
    "path": "docs/useDefault.md",
    "content": "# `useDefault`\n\nReact state hook that returns the default value when state is null or undefined.\n\n## Usage\n\n```jsx\nimport {useDefault} from 'react-use';\n\nconst Demo = () => {\n  const initialUser = { name: 'Marshall' }\n  const defaultUser = { name: 'Mathers' }\n  const [user, setUser] = useDefault(defaultUser, initialUser);\n\n  return (\n    <div>\n      <div>User: {user.name}</div>\n      <input onChange={e => setUser({ name: e.target.value })} />\n      <button onClick={() => setUser(null)}>set to null</button>\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useDrop.md",
    "content": "# `useDrop` and `useDropArea`\n\nTriggers on file, link drop and copy-paste.\n\n`useDrop` tracks events for the whole page, `useDropArea` tracks drop events\nfor a specific element.\n\n\n## Usage\n\n`useDrop`:\n\n```jsx\nimport {useDrop} from 'react-use';\n\nconst Demo = () => {\n  const state = useDrop({\n    onFiles: files => console.log('files', files),\n    onUri: uri => console.log('uri', uri),\n    onText: text => console.log('text', text),\n  });\n\n  return (\n    <div>\n      Drop something on the page.\n    </div>\n  );\n};\n```\n\n`useDropArea`:\n\n```jsx\nimport {useDropArea} from 'react-use';\n\nconst Demo = () => {\n  const [bond, state] = useDropArea({\n    onFiles: files => console.log('files', files),\n    onUri: uri => console.log('uri', uri),\n    onText: text => console.log('text', text),\n  });\n\n  return (\n    <div {...bond}>\n      Drop something here.\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useEffectOnce.md",
    "content": "# `useEffectOnce`\n\nReact lifecycle hook that runs an effect only once.\n\n## Usage\n\n```jsx\nimport {useEffectOnce} from 'react-use';\n\nconst Demo = () => {\n  useEffectOnce(() => {\n    console.log('Running effect once on mount')\n\n    return () => {\n      console.log('Running clean-up of effect on unmount')\n    }\n  });\n\n  return null;\n};\n```\n\n## Reference\n\n```js\nuseEffectOnce(effect: EffectCallback);\n```\n"
  },
  {
    "path": "docs/useEnsuredForwardedRef.md",
    "content": "# `useEnsuredForwardedRef`\n\nReact hook to use a ForwardedRef safely.\n\nIn some scenarios, you may need to use a _ref_ from inside and outside a component. If that's the case, you should use `React.forwardRef` to pass it through the child component. This is useful when you only want to forward that _ref_ and expose an internal `HTMLelement` to a parent component, for example. However, if you need to manipulate that reference inside a child's lifecycle hook... things get complicated, since you can't always ensure that the _ref_ is being sent by the parent component and if it is not, you will get `undefined` instead of a valid _ref_.\n\nThis hook is useful in this specific case, it will __ensure__ that you get a valid reference on the other side.\n\n## Usage\n\n```jsx\nimport {ensuredForwardRef} from 'react-use';\n\nconst Demo = () => {\n  return (\n    <Child />\n  );\n};\n\nconst Child = ensuredForwardRef((props, ref) => {\n  useEffect(() => {\n    console.log(ref.current.getBoundingClientRect())\n  }, [])\n\n  return (\n    <div ref={ref} />\n  );\n});\n```\n\n## Alternative usage\n\n```jsx\nimport {useEnsuredForwardedRef} from 'react-use';\n\nconst Demo = () => {\n  return (\n    <Child />\n  );\n};\n\nconst Child = React.forwardRef((props, ref) => {\n  // Here `ref` is undefined\n  const ensuredForwardRef = useEnsuredForwardedRef(ref);\n  // ensuredForwardRef will always be a valid reference.\n\n  useEffect(() => {\n    console.log(ensuredForwardRef.current.getBoundingClientRect())\n  }, [])\n\n  return (\n    <div ref={ensuredForwardRef} />\n  );\n});\n```\n\n## Reference\n\n```ts\nensuredForwardRef<T, P = {}>(Component: RefForwardingComponent<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;\n\nuseEnsuredForwardedRef<T>(ref: React.MutableRefObject<T>): React.MutableRefObject<T>;\n```\n"
  },
  {
    "path": "docs/useError.md",
    "content": "# `useError`\n\nReact side-effect hook that returns an error dispatcher.\n\n## Usage\n\n```jsx\nimport { useError } from 'react-use';\n\nconst Demo = () => {\n  const dispatchError = useError();\n\n  const clickHandler = () => {\n    dispatchError(new Error('Some error!'));\n  };\n\n  return <button onClick={clickHandler}>Click me to throw</button>;\n};\n\n// In parent app\nconst App = () => (\n  <ErrorBoundary>\n    <Demo />\n  </ErrorBoundary>\n);\n```\n\n## Reference\n\n```js\nconst dispatchError = useError();\n```\n\n- `dispatchError` &mdash; Callback of type `(err: Error) => void`\n"
  },
  {
    "path": "docs/useEvent.md",
    "content": "# `useEvent`\n\nReact sensor hook that subscribes a `handler` to events.\n\n\n## Usage\n\n```jsx\nimport {useEvent, useList} from 'react-use';\n\nconst Demo = () => {\n  const [list, {push, clear}] = useList();\n\n  const onKeyDown = useCallback(({key}) => {\n    if (key === 'r') clear();\n    push(key);\n  }, []);\n\n  useEvent('keydown', onKeyDown);\n\n  return (\n    <div>\n      <p>\n        Press some keys on your keyboard, <code style={{color: 'tomato'}}>r</code> key resets the list\n      </p>\n      <pre>\n        {JSON.stringify(list, null, 4)}\n      </pre>\n    </div>\n  );\n};\n```\n\n\n## Examples\n\n```js\nuseEvent('keydown', handler)\nuseEvent('scroll', handler, window, {capture: true})\n```\n"
  },
  {
    "path": "docs/useFavicon.md",
    "content": "# `useFavicon`\n\nReact side-effect hook sets the favicon of the page.\n\n\n## Usage\n\n```jsx\nimport {useFavicon} from 'react-use';\n\nconst Demo = () => {\n  useFavicon('https://cdn.sstatic.net/Sites/stackoverflow/img/favicon.ico');\n\n  return null;\n};\n```\n"
  },
  {
    "path": "docs/useFirstMountState.md",
    "content": "# `useFirstMountState`\n\nReturns `true` if component is just mounted (on first render) and `false` otherwise.\n\n## Usage\n\n```typescript jsx\nimport * as React from 'react';\nimport { useFirstMountState } from 'react-use';\n\nconst Demo = () => {\n  const isFirstMount = useFirstMountState();\n  const update = useUpdate();\n\n  return (\n    <div>\n      <span>This component is just mounted: {isFirstMount ? 'YES' : 'NO'}</span>\n      <br />\n      <button onClick={update}>re-render</button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```typescript\nconst isFirstMount: boolean = useFirstMountState();\n```\n"
  },
  {
    "path": "docs/useFullscreen.md",
    "content": "# `useFullscreen`\n\nDisplay an element full-screen, optional fallback for fullscreen video on iOS.\n\n## Usage\n\n```jsx\nimport {useFullscreen, useToggle} from 'react-use';\n\nconst Demo = () => {\n  const ref = useRef(null)\n  const [show, toggle] = useToggle(false);\n  const isFullscreen = useFullscreen(ref, show, {onClose: () => toggle(false)});\n\n  return (\n    <div ref={ref} style={{backgroundColor: 'white'}}>\n      <div>{isFullscreen ? 'Fullscreen' : 'Not fullscreen'}</div>\n      <button onClick={() => toggle()}>Toggle</button>\n      <video src=\"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4\" autoPlay />\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseFullscreen(ref, show, {onClose})\n```\n"
  },
  {
    "path": "docs/useGeolocation.md",
    "content": "# `useGeolocation`\n\nReact sensor hook that tracks user's geographic location. This hook accepts [position options](https://developer.mozilla.org/docs/Web/API/PositionOptions).\n\n## Usage\n\n```jsx\nimport {useGeolocation} from 'react-use';\n\nconst Demo = () => {\n  const state = useGeolocation();\n\n  return (\n    <pre>\n      {JSON.stringify(state, null, 2)}\n    </pre>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseGeolocation(options: PositionOptions)\n```\n"
  },
  {
    "path": "docs/useGetSet.md",
    "content": "# `useGetSet`\n\nReact state hook that returns state getter function instead of\nraw state itself, this prevents subtle bugs when state is used\nin nested functions.\n\n\n## Usage\n\nBelow example uses `useGetSet` to increment a number after 1 second\non each click.\n\n```jsx\nimport {useGetSet} from 'react-use';\n\nconst Demo = () => {\n  const [get, set] = useGetSet(0);\n  const onClick = () => {\n    setTimeout(() => {\n      set(get() + 1)\n    }, 1_000);\n  };\n\n  return (\n    <button onClick={onClick}>Clicked: {get()}</button>\n  );\n};\n```\n\nIf you would do this example in a naive way using regular `useState`\nhook, the counter would not increment correctly if you click fast multiple times.\n\n```jsx\nconst DemoWrong = () => {\n  const [cnt, set] = useState(0);\n  const onClick = () => {\n    setTimeout(() => {\n      set(cnt + 1)\n    }, 1_000);\n  };\n\n  return (\n    <button onClick={onClick}>Clicked: {cnt}</button>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useGetSetState.md",
    "content": "# `useGetSetState`\n\nA mix of `useGetSet` and `useGetSetState`.\n\n\n## Usage\n\n```jsx\nimport {useGetSetState} from 'react-use';\n\nconst Demo = () => {\n  const [get, setState] = useGetSetState({cnt: 0});\n  const onClick = () => {\n    setTimeout(() => {\n      setState({cnt: get().cnt + 1})\n    }, 1000);\n  };\n\n  return (\n    <button onClick={onClick}>Clicked: {get().cnt}</button>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useHarmonicIntervalFn.md",
    "content": "# `useHarmonicIntervalFn`\n\nSame as [`useInterval`](./useInterval.md) hook, but triggers all effects with the same delay\nat the same time.\n\nFor example, this allows you to create ticking clocks on the page which re-render second counter\nall at the same time.\n\n\n## Reference\n\n```js\nuseHarmonicIntervalFn(fn, delay?: number)\n```\n"
  },
  {
    "path": "docs/useHash.md",
    "content": "# `useHash`\n\nReact sensor hook that tracks browser's location hash.\n\n## Usage\n\n```jsx\nimport {useHash} from 'react-use';\n\nconst Demo = () => {\n  const [hash, setHash] = useHash();\n\n  useMount(() => {\n    setHash('#/path/to/page?userId=123');\n  });\n\n  return (\n    <div>\n      <div>window.location.href:</div>\n      <div>\n        <pre>{window.location.href}</pre>\n      </div>\n      <div>Edit hash: </div>\n      <div>\n        <input style={{ width: '100%' }} value={hash} onChange={e => setHash(e.target.value)} />\n      </div>\n    </div>\n  );\n};\n```\n\n## API\n\n`const [hash, setHash] = useHash()`\n\nGet latest url hash with `hash` and set url hash with `setHash`.\n\n- `hash: string`: get current url hash. listen to `hashchange` event.\n- `setHash: (newHash: string) => void`: change url hash. Invoke this method will trigger `hashchange` event."
  },
  {
    "path": "docs/useHover.md",
    "content": "# `useHover` and `useHoverDirty`\n\nReact UI sensor hooks that track if some element is being hovered\nby a mouse.\n\n- `useHover` accepts a React element or a function that returns one,\n`useHoverDirty` accepts React ref.\n- `useHover` sets react `onMouseEnter` and `onMouseLeave` events,\n`useHoverDirty` sets DOM `onmouseover` and `onmouseout` events.\n\n\n## Usage\n\n```jsx\nimport {useHover} from 'react-use';\n\nconst Demo = () => {\n  const element = (hovered) =>\n    <div>\n      Hover me! {hovered && 'Thanks!'}\n    </div>;\n  const [hoverable, hovered] = useHover(element);\n\n  return (\n    <div>\n      {hoverable}\n      <div>{hovered ? 'HOVERED' : ''}</div>\n    </div>\n  );\n};\n```\n\n\n## Reference\n\n```js\nconst [newReactElement, isHovering] = useHover(reactElement);\nconst [newReactElement, isHovering] = useHover((isHovering) => reactElement);\nconst isHovering = useHoverDirty(ref);\n```\n"
  },
  {
    "path": "docs/useIdle.md",
    "content": "# `useIdle`\n\nReact sensor hook that tracks if user on the page is idle.\n\n\n## Usage\n\n```jsx\nimport {useIdle} from 'react-use';\n\nconst Demo = () => {\n  const isIdle = useIdle(3e3);\n\n  return (\n    <div>\n      <div>User is idle: {isIdle ? 'Yes 😴' : 'Nope'}</div>\n    </div>\n  );\n};\n```\n\n\n## Reference\n\n```js\nuseIdle(ms, initialState);\n```\n\n- `ms` &mdash; time in milliseconds after which to consider use idle, defaults to `60e3` &mdash; one minute.\n- `initialState` &mdash; whether to consider user initially idle, defaults to false.\n"
  },
  {
    "path": "docs/useIntersection.md",
    "content": "# `useIntersection`\n\nReact sensor hook that tracks the changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. Uses the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) and returns a [IntersectionObserverEntry](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry).\n\n## Usage\n\n```jsx\nimport * as React from 'react';\nimport { useIntersection } from 'react-use';\n\nconst Demo = () => {\n  const intersectionRef = React.useRef(null);\n  const intersection = useIntersection(intersectionRef, {\n    root: null,\n    rootMargin: '0px',\n    threshold: 1\n  });\n\n  return (\n    <div ref={intersectionRef}>\n      {intersection && intersection.intersectionRatio < 1\n        ? 'Obscured'\n        : 'Fully in view'}\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseIntersection(\n  ref: RefObject<HTMLElement>,\n  options: IntersectionObserverInit,\n): IntersectionObserverEntry | null;\n```\n"
  },
  {
    "path": "docs/useInterval.md",
    "content": "# `useInterval`\n\nA declarative interval hook based on [Dan Abramov's article on overreacted.io](https://overreacted.io/making-setinterval-declarative-with-react-hooks). The interval can be paused by setting the delay to `null`.\n\n## Usage\n\n```jsx\nimport * as React from 'react';\nimport {useInterval} from 'react-use';\n\nconst Demo = () => {\n  const [count, setCount] = React.useState(0);\n  const [delay, setDelay] = React.useState(1000);\n  const [isRunning, toggleIsRunning] = useBoolean(true);\n\n  useInterval(\n    () => {\n      setCount(count + 1);\n    },\n    isRunning ? delay : null\n  );\n\n  return (\n    <div>\n      <div>\n        delay: <input value={delay} onChange={event => setDelay(Number(event.target.value))} />\n      </div>\n      <h1>count: {count}</h1>\n      <div>\n        <button onClick={toggleIsRunning}>{isRunning ? 'stop' : 'start'}</button>\n      </div>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```js\nuseInterval(callback, delay?: number)\n```\n"
  },
  {
    "path": "docs/useIsomorphicLayoutEffect.md",
    "content": "# `useIsomorphicLayoutEffect`\n\n`useLayoutEffect` that does not show warning when server-side rendering, see [Alex Reardon's article](https://medium.com/@alexandereardon/uselayouteffect-and-ssr-192986cdcf7a) for more info.\n\n## Usage\n\n```jsx\nimport {useIsomorphicLayoutEffect} from 'react-use';\n\nconst Demo = ({value}) => {\n  useIsomorphicLayoutEffect(() => {\n    window.console.log(value)\n  }, [value]);\n\n  return null;\n};\n```\n\n\n## Reference\n\n```ts\nuseIsomorphicLayoutEffect(effect: EffectCallback, deps?: ReadonlyArray<any> | undefined);\n```\n"
  },
  {
    "path": "docs/useKey.md",
    "content": "# `useKey`\n\nReact UI sensor hook that executes a `handler` when a keyboard key is used.\n\n## Usage\n\n```jsx\nimport {useKey} from 'react-use';\n\nconst Demo = () => {\n  const [count, set] = useState(0);\n  const increment = () => set(count => ++count);\n  useKey('ArrowUp', increment);\n\n  return (\n    <div>\n      Press arrow up: {count}\n    </div>\n  );\n};\n```\n\nOr as render-prop:\n\n```jsx\nimport UseKey from 'react-use/lib/component/UseKey';\n\n<UseKey filter='a' fn={() => alert('\"a\" key pressed!')} />\n```\n\n\n## Reference\n\n```js\nuseKey(filter, handler, options?, deps?)\n```\n\n\n## Examples\n\n```js\nuseKey('a', () => alert('\"a\" pressed'));\n\nconst predicate = (event) => event.key === 'a'\nuseKey(predicate, handler, {event: 'keyup'});\n```\n"
  },
  {
    "path": "docs/useKeyPress.md",
    "content": "# `useKeyPress`\n\nReact UI sensor hook that detects when the user is pressing a specific\nkey on their keyboard.\n\n\n## Usage\n\n```jsx\nimport {useKeyPress} from 'react-use';\n\nconst keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];\n\nconst Demo = () => {\n  const states = [];\n  for (const key of keys) states.push(useKeyPress(key)[0]);\n\n  return (\n    <div style={{textAlign: 'center'}}>\n      Try pressing numbers\n      <br />\n      {states.reduce((s, pressed, index) => s + (pressed ? (s ? ' + ' : '') + keys[index] : ''), '')}\n    </div>\n  );\n};\n```\n\n\n## Examples\n\n```js\nconst isPressed = useKeyPress('a');\n\nconst predicate = (event) => event.key === 'a';\nconst isPressed = useKeyPress(predicate);\n```\n"
  },
  {
    "path": "docs/useKeyPressEvent.md",
    "content": "# `useKeyPressEvent`\n\nThis hook fires `keydown` and `keyup` callbacks, similar to how [`useKey`](./useKey.md)\nhook does, but it only triggers each callback once per press cycle. For example,\nif you press and hold a key, it will fire `keydown` callback only once.\n\n\n## Usage\n\n```jsx\nimport React, { useState } from React;\nimport {useKeyPressEvent} from 'react-use';\n\nconst Demo = () => {\n  const [count, setCount] = useState(0);\n\n  const increment = () => setCount(count => ++count);\n  const decrement = () => setCount(count => --count);\n  const reset = () => setCount(count => 0);\n\n  useKeyPressEvent(']', increment, increment);\n  useKeyPressEvent('[', decrement, decrement);\n  useKeyPressEvent('r', reset);\n\n  return (\n    <div>\n      <p>\n        Try pressing <code>[</code>, <code>]</code>, and <code>r</code> to\n        see the count incremented and decremented.</p>\n      <p>Count: {count}</p>\n    </div>\n  );\n};\n```\n\n\n## Reference\n\n```js\nuseKeyPressEvent('<key>', keydown);\nuseKeyPressEvent('<key>', keydown, keyup);\nuseKeyPressEvent('<key>', keydown, keyup, useKeyPress);\n```\n"
  },
  {
    "path": "docs/useKeyboardJs.md",
    "content": "# `useKeyboardJs`\n\nReact UI sensor hook that detects complex key combos like detecting when\nmultiple keys are held down at the same time or requiring them to be held down in a specified order.\n\nVia [KeyboardJS key combos](https://github.com/RobertWHurst/KeyboardJS).\nCheck its documentation for further details on how to make combo strings.\n\n## Usage\n\n```jsx\nimport useKeyboardJs from 'react-use/lib/useKeyboardJs';\n\nconst Demo = () => {\n  const [isPressed] = useKeyboardJs('a + b');\n\n  return (\n    <div>\n      [a + b] pressed: {isPressed ? 'Yes' : 'No'}\n    </div>\n  );\n};\n```\n\nNote: Because of dependency on `keyboardjs` you have to import this hook directly like shown above.\n\n## Requirements\n\nInstall [`keyboardjs`](https://github.com/RobertWHurst/KeyboardJS) peer dependency:\n\n```bash\nnpm add keyboardjs\n# or\nyarn add keyboardjs\n```\n\n## Reference\n\n```js\nuseKeyboardJs(combination: string | string[]): [isPressed: boolean, event?: KeyboardEvent]\n```\n"
  },
  {
    "path": "docs/useLatest.md",
    "content": "# `useLatest`\n\nReact state hook that returns the latest state as described in the [React hooks FAQ](https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function).\n\nThis is mostly useful to get access to the latest value of some props or state inside an asynchronous callback, instead of that value at the time the callback was created from.\n\n## Usage\n\n```jsx\nimport { useLatest } from 'react-use';\n\nconst Demo = () => {\n  const [count, setCount] = React.useState(0);\n  const latestCount = useLatest(count);\n\n  function handleAlertClick() {\n    setTimeout(() => {\n      alert(`Latest count value: ${latestCount.current}`);\n    }, 3000);\n  }\n\n  return (\n    <div>\n      <p>You clicked {count} times</p>\n      <button onClick={() => setCount(count + 1)}>Click me</button>\n      <button onClick={handleAlertClick}>Show alert</button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nconst latestState = useLatest = <T>(state: T): MutableRefObject<T>;\n```\n"
  },
  {
    "path": "docs/useLifecycles.md",
    "content": "# `useLifecycles`\n\nReact lifecycle hook that call `mount` and `unmount` callbacks, when\ncomponent is mounted and un-mounted, respectively.\n\n\n## Usage\n\n```jsx\nimport {useLifecycles} from 'react-use';\n\nconst Demo = () => {\n  useLifecycles(() => console.log('MOUNTED'), () => console.log('UNMOUNTED'));\n  return null;\n};\n```\n\n\n## Reference\n\n```js\nuseLifecycles(mount, unmount);\n```\n"
  },
  {
    "path": "docs/useList.md",
    "content": "# `useList`\n\nTracks an array and provides methods to modify it.  \nTo cause component re-render you have to use these methods instead of direct interaction with array - it won't cause re-render.\n\nWe can ensure that actions object and actions itself will not mutate or change between renders, so there is no need to add it to useEffect dependencies and safe to pass them down to children.  \n\n**Note:** `remove` action is deprecated and actually is a copy of `removeAt` action. Within closest updates it will gain different functionality.\n\n## Usage\n\n```jsx\nimport {useList} from 'react-use';\n\nconst Demo = () => {\n  const [list, { set, push, updateAt, insertAt, update, updateFirst, upsert, sort, filter, removeAt, clear, reset }] = useList([1, 2, 3, 4, 5]);\n\n  return (\n    <div>\n      <button onClick={() => set([1, 2, 3])}>Set to [1, 2, 3]</button>\n      <button onClick={() => push(Date.now())}>Push timestamp</button>\n      <button onClick={() => updateAt(1, Date.now())}>Update value at index 1</button>\n      <button onClick={() => remove(1)}>Remove element at index 1</button>\n      <button onClick={() => filter(item => item % 2 === 0)}>Filter even values</button>\n      <button onClick={() => sort((a, b) => a - b)}>Sort ascending</button>\n      <button onClick={() => sort((a, b) => b - a)}>Sort descending</button>\n      <button onClick={clear}>Clear</button>\n      <button onClick={reset}>Reset</button>\n      <pre>{JSON.stringify(list, null, 2)}</pre>\n    </div>\n  );\n};\n```\n\n## Reference\n```ts\nimport {useList} from \"react-use\";\n\nconst [list, { \n    set, \n    push, \n    updateAt, \n    insertAt, \n    update, \n    updateFirst,\n    upsert, \n    sort, \n    filter, \n    removeAt, \n    remove, \n    clear, \n    reset \n}] = useList(array: any[] | ()=> any[]);\n```\n\n- **`list`**_`: T{}`_ &mdash; current list;\n- **`set`**_`: (list: T[]) => void;`_ &mdash; Set new list instead old one;\n- **`push`**_`: (...items: T[]) => void;`_ &mdash; Add item(s) at the end of list;\n- **`updateAt`**_`: (index: number, item: T) => void;`_ &mdash; Replace item at given position. If item at given position not exists it will be set;\n- **`insertAt`**_`: (index: number, item: T) => void;`_ &mdash; Insert item at given position, all items to the right will be shifted;\n- **`update`**_`: (predicate: (a: T, b: T) => boolean, newItem: T) => void;`_ &mdash; Replace all items that matches predicate with given one;\n- **`updateFirst`**_`: (predicate: (a: T, b: T) => boolean, newItem: T) => void;`_ &mdash; Replace first item matching predicate with given one;\n- **`upsert`**_`: (predicate: (a: T, b: T) => boolean, newItem: T) => void;`_ &mdash; Like `updateFirst` but in case of predicate miss - pushes item to the list;\n- **`sort`**_`: (compareFn?: (a: T, b: T) => number) => void;`_ &mdash; Sort list with given sorting function;\n- **`filter`**_`: (callbackFn: (value: T, index?: number, array?: T[]) => boolean, thisArg?: any) => void;`_ &mdash; Same as native Array's method;\n- **`removeAt`**_`: (index: number) => void;`_ &mdash; Removes item at given position. All items to the right from removed will be shifted;\n- **`remove`**_`: (index: number) => void;`_ &mdash; _**DEPRECATED:**_ Use removeAt method instead;\n- **`clear`**_`: () => void;`_ &mdash; Make the list empty;\n- **`reset`**_`: () => void;`_ &mdash; Reset list to initial value;\n\n## Related hooks\n\n- [useUpsert](./useUpsert.md)\n"
  },
  {
    "path": "docs/useLocalStorage.md",
    "content": "# `useLocalStorage`\n\nReact side-effect hook that manages a single `localStorage` key.\n\n## Usage\n\n```jsx\nimport { useLocalStorage } from 'react-use';\n\nconst Demo = () => {\n  const [value, setValue, remove] = useLocalStorage('my-key', 'foo');\n\n  return (\n    <div>\n      <div>Value: {value}</div>\n      <button onClick={() => setValue('bar')}>bar</button>\n      <button onClick={() => setValue('baz')}>baz</button>\n      <button onClick={() => remove()}>Remove</button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```js\nuseLocalStorage(key);\nuseLocalStorage(key, initialValue);\nuseLocalStorage(key, initialValue, { raw: true });\nuseLocalStorage(key, initialValue, {\n  raw: false,\n  serializer: (value: T) => string,\n  deserializer: (value: string) => T,\n});\n```\n\n- `key` &mdash; `localStorage` key to manage.\n- `initialValue` &mdash; initial value to set, if value in `localStorage` is empty.\n- `raw` &mdash; boolean, if set to `true`, hook will not attempt to JSON serialize stored values.\n- `serializer` &mdash; custom serializer (defaults to `JSON.stringify`)\n- `deserializer` &mdash; custom deserializer (defaults to `JSON.parse`)\n"
  },
  {
    "path": "docs/useLocation.md",
    "content": "# `useLocation`\n\nReact sensor hook that tracks brower's location.\n\nFor Internet Explorer you need to [install a polyfill](https://github.com/streamich/react-use/issues/73).\n\n\n## Usage\n\n```jsx\nimport {useLocation} from 'react-use';\n\nconst Demo = () => {\n  const state = useLocation();\n\n  return (\n    <pre>\n      {JSON.stringify(state, null, 2)}\n    </pre>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useLockBodyScroll.md",
    "content": "# `useLockBodyScroll`\n\nReact side-effect hook that locks scrolling on the body element. Useful for modal and other overlay components.\n\nAccepts ref object pointing to any HTML element as second parameter. Parent body element will be found and it's scroll will be locked/unlocked. It is needed to proper iFrame handling.  \nBy default it uses body element of script's parent window. \n\n>Note: To improve performance you can pass body's or iframe's ref object, thus no parent lookup will be performed \n\n## Usage \n\n```jsx\nimport {useLockBodyScroll, useToggle} from 'react-use';\n\nconst Demo = () => {\n  const [locked, toggleLocked] = useToggle(false)\n\n  useLockBodyScroll(locked);\n\n  return (\n    <div>\n      <button onClick={() => toggleLocked()}>\n        {locked ? 'Unlock' : 'Lock'}\n      </button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseLockBodyScroll(locked: boolean = true, elementRef?: RefObject<HTMLElement>);\n```\n\n- `locked` &mdash; Hook will lock scrolling on the body element if `true`, defaults to `true`\n- `elementRef` &mdash; The element ref object to find the body element. Can be either a ref to body or iframe element.\n"
  },
  {
    "path": "docs/useLogger.md",
    "content": "# `useLogger`\n\nReact lifecycle hook that console logs parameters as component transitions through lifecycles.\n\n## Usage\n\n```jsx\nimport {useLogger} from 'react-use';\n\nconst Demo = (props) => {\n  useLogger('Demo', props);\n  return null;\n};\n```\n\n## Example Output\n\n```\nDemo mounted {}\nDemo updated {}\nDemo unmounted\n```\n\n## Reference\n\n```js\nuseLogger(componentName: string, ...rest);\n```\n\n- `componentName` &mdash; component name.\n- `...rest` &mdash; parameters to log.\n"
  },
  {
    "path": "docs/useLongPress.md",
    "content": "# `useLongPress`\n\nReact sensor hook that fires a callback after long pressing.\n\n## Usage\n\n```jsx\nimport { useLongPress } from 'react-use';\n\nconst Demo = () => {\n  const onLongPress = () => {\n    console.log('calls callback after long pressing 300ms');\n  };\n\n  const defaultOptions = {\n    isPreventDefault: true,\n    delay: 300,\n  };\n  const longPressEvent = useLongPress(onLongPress, defaultOptions);\n\n  return <button {...longPressEvent}>useLongPress</button>;\n};\n```\n\n## Reference\n\n```ts\nconst {\n  onMouseDown,\n  onTouchStart,\n  onMouseUp,\n  onMouseLeave,\n  onTouchEnd\n} = useLongPress(\n  callback: (e: TouchEvent | MouseEvent) => void,\n  options?: {\n    isPreventDefault?: true,\n    delay?: 300\n  }\n)\n```\n\n- `callback` &mdash; callback function.\n- `options?` &mdash; optional parameter.\n  - `isPreventDefault?` &mdash; whether to call `event.preventDefault()` of `touchend` event, for preventing ghost click on mobile devices in some cases, defaults to `true`.\n  - `delay?` &mdash; delay in milliseconds after which to calls provided callback, defaults to `300`.\n"
  },
  {
    "path": "docs/useMap.md",
    "content": "# `useMap`\n\nReact state hook that tracks a value of an object.\n\n## Usage\n\n```jsx\nimport {useMap} from 'react-use';\n\nconst Demo = () => {\n  const [map, {set, setAll, remove, reset}] = useMap({\n    hello: 'there',\n  });\n\n  return (\n    <div>\n      <button onClick={() => set(String(Date.now()), new Date().toJSON())}>\n        Add\n      </button>\n      <button onClick={() => reset()}>\n        Reset\n      </button>\n      <button onClick={() => setAll({ hello: 'new', data: 'data' })}>\n        Set new data\n      </button>\n      <button onClick={() => remove('hello')} disabled={!map.hello}>\n        Remove 'hello'\n      </button>\n      <pre>{JSON.stringify(map, null, 2)}</pre>\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useMeasure.md",
    "content": "# `useMeasure`\n\nReact sensor hook that tracks dimensions of an HTML element using the [Resize Observer API](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).\n\n## Usage\n\n```jsx\nimport { useMeasure } from \"react-use\";\n\nconst Demo = () => {\n  const [ref, { x, y, width, height, top, right, bottom, left }] = useMeasure();\n\n  return (\n    <div ref={ref}>\n      <div>x: {x}</div>\t\n      <div>y: {y}</div>\n      <div>width: {width}</div>\n      <div>height: {height}</div>\n      <div>top: {top}</div>\n      <div>right: {right}</div>\n      <div>bottom: {bottom}</div>\n      <div>left: {left}</div>\n    </div>\n  );\n};\n```\n\nThis hook uses [`ResizeObserver` API][resize-observer], if you want to support \nlegacy browsers, consider installing [`resize-observer-polyfill`][resize-observer-polyfill] \nbefore running your app. \n\n```js\nif (!window.ResizeObserver) {\n  window.ResizeObserver = (await import('resize-observer-polyfill')).default;\n}\n```\n\n\n## Related hooks\n\n- [useSize](./useSize.md)\n\n\n[resize-observer]: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver\n[resize-observer-polyfill]: https://www.npmjs.com/package/resize-observer-polyfill\n"
  },
  {
    "path": "docs/useMedia.md",
    "content": "# `useMedia`\n\nReact sensor hook that tracks state of a CSS media query.\n\n## Usage\n\n```jsx\nimport {useMedia} from 'react-use';\n\nconst Demo = () => {\n  const isWide = useMedia('(min-width: 480px)');\n\n  return (\n    <div>\n      Screen is wide: {isWide ? 'Yes' : 'No'}\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseMedia(query: string, defaultState: boolean = false): boolean;\n```\n\nThe `defaultState` parameter is only used as a fallback for server side rendering.\n\nWhen server side rendering, it is important to set this parameter because without it the server's initial state will fallback to false, but the client will initialize to the result of the media query. When React hydrates the server render, it may not match the client's state. See the [React docs](https://reactjs.org/docs/react-dom.html#hydrate) for more on why this is can lead to costly bugs 🐛.\n"
  },
  {
    "path": "docs/useMediaDevices.md",
    "content": "# `useMediaDevices`\n\nReact sensor hook that tracks connected hardware devices.\n\n\n## Usage\n\n```jsx\nimport {useMediaDevices} from 'react-use';\n\nconst Demo = () => {\n  const state = useMediaDevices();\n\n  return (\n    <pre>\n      {JSON.stringify(state, null, 2)}\n    </pre>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useMediatedState.md",
    "content": "# `useMediatedState`\n\nA lot like the standard `useState`, but with mediation process.\n\n## Usage\n```ts\nimport * as React from 'react';\nimport { useMediatedState } from '../useMediatedState';\n\nconst inputMediator = s => s.replace(/[\\s]+/g, ' ');\nconst Demo = () => {\n  const [state, setState] = useMediatedState(inputMediator, '');\n\n  return (\n    <div>\n      <div>You will not be able to enter more than one space</div>\n      <input type=\"text\" min=\"0\" max=\"10\" \n             value={state}\n             onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {\n               setState(ev.target.value);\n             }}\n      />\n    </div>\n  );\n};\n```\n\n## Reference\n```ts\nconst [state, setState] = useMediatedState<S=any>(\n  mediator: StateMediator<S>,\n  initialState?: S\n);\n```\n\n> Initial state will be set as-is.\n\nIn case mediator expects 2 arguments it will receive the `setState` function as second argument, it is useful for async mediators.  \n>This hook will not cancel previous mediation when new one been invoked, you have to handle it yourself._\n"
  },
  {
    "path": "docs/useMethods.md",
    "content": "# `useMethods`\n\nReact hook that simplifies the `useReducer` implementation.\n\n## Usage\n\n```jsx\nimport { useMethods } from 'react-use';\n\nconst initialState = {\n  count: 0,\n};\n\nfunction createMethods(state) {\n  return {\n    reset() {\n      return initialState;\n    },\n    increment() {\n      return { ...state, count: state.count + 1 };\n    },\n    decrement() {\n      return { ...state, count: state.count - 1 };\n    },\n  };\n}\n\nconst Demo = () => {\n  const [state, methods] = useMethods(createMethods, initialState);\n\n  return (\n    <>\n      <p>Count: {state.count}</p>\n      <button onClick={methods.decrement}>-</button>\n      <button onClick={methods.increment}>+</button>\n    </>\n  );\n};\n```\n\n## Reference\n\n```js\nconst [state, methods] = useMethods(createMethods, initialState);\n```\n\n- `createMethods` &mdash; function that takes current state and return an object containing methods that return updated state.\n- `initialState` &mdash; initial value of the state.\n"
  },
  {
    "path": "docs/useMotion.md",
    "content": "# `useMotion`\n\nReact sensor hook that uses device's acceleration sensor to track its motions.\n\n\n## Usage\n\n```jsx\nimport {useMotion} from 'react-use';\n\nconst Demo = () => {\n  const state = useMotion();\n\n  return (\n    <pre>\n      {JSON.stringify(state, null, 2)}\n    </pre>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useMount.md",
    "content": "# `useMount`\n\nReact lifecycle hook that calls a function after the component is mounted. Use `useLifecycles` if you need both a mount and unmount function.\n\n## Usage\n\n```jsx\nimport {useMount} from 'react-use';\n\nconst Demo = () => {\n  useMount(() => alert('MOUNTED'));\n  return null;\n};\n```\n\n## Reference\n\n```ts\nuseMount(fn: () => void);\n```\n"
  },
  {
    "path": "docs/useMountedState.md",
    "content": "# `useMountedState`\n\n> **NOTE!:** despite having `State` in its name **_this hook does not cause component re-render_**.  \n> This component designed to be used to avoid state updates on unmounted components.\n\nLifecycle hook providing ability to check component's mount state.  \nReturns a function that will return `true` if component mounted and `false` otherwise.\n\n## Usage\n\n```jsx\nimport * as React from 'react';\nimport {useMountedState} from 'react-use';\n\nconst Demo = () => {\n  const isMounted = useMountedState();\n\n  React.useEffect(() => {\n    setTimeout(() => {\n      if (isMounted()) {\n        // ...\n      } else {\n        // ...\n      }\n    }, 1000);\n  });\n};\n```\n"
  },
  {
    "path": "docs/useMouse.md",
    "content": "# `useMouse` and `useMouseHovered`\n\nReact sensor hooks that re-render on mouse position changes. `useMouse` simply tracks\nmouse position; `useMouseHovered` allows you to specify extra options:\n\n- `bound` &mdash; to bind mouse coordinates within the element\n- `whenHovered` &mdash; whether to attach `mousemove` event handler only when user hovers over the element\n\n## Usage\n\n```jsx\nimport {useMouse} from 'react-use';\n\nconst Demo = () => {\n  const ref = React.useRef(null);\n  const {docX, docY, posX, posY, elX, elY, elW, elH} = useMouse(ref);\n\n  return (\n    <div ref={ref}>\n      <div>Mouse position in document - x:{docX} y:{docY}</div>\n      <div>Mouse position in element - x:{elX} y:{elY}</div>\n      <div>Element position- x:{posX} y:{posY}</div>\n      <div>Element dimensions - {elW}x{elH}</div>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseMouse(ref);\nuseMouseHovered(ref, {bound: false, whenHovered: false});\n```\n"
  },
  {
    "path": "docs/useMouseWheel.md",
    "content": "# `useMouseWheel` \nReact Hook to get deltaY of mouse scrolled in window. \n\n## Usage\n\n```jsx\nimport { useMouseWheel } from 'react-use';\n\nconst Demo = () => {\n  const mouseWheel = useMouseWheel()\n  return (\n    <>\n      <h3>delta Y Scrolled: {mouseWheel}</h3>\n    </>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useMultiStateValidator.md",
    "content": "# `useMultiStateValidator`\n\nEach time any of given states changes - validator function is invoked.  \n\n## Usage\n```ts \nimport * as React from 'react';\nimport { useMultiStateValidator } from 'react-use';\n\nconst DemoStateValidator = (s: number[]) => [s.every((num: number) => !(num % 2))] as [boolean];\nconst Demo = () => {\n  const [state1, setState1] = React.useState<number>(1);\n  const [state2, setState2] = React.useState<number>(1);\n  const [state3, setState3] = React.useState<number>(1);\n  const [[isValid]] = useMultiStateValidator([state1, state2, state3], DemoStateValidator);\n\n  return (\n    <div>\n      <div>Below fields will be valid if all of them is even</div>\n      <input type=\"number\" min=\"1\" max=\"10\" value={state1}\n        onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {\n          setState1((ev.target.value as unknown) as number);\n        }}\n      />\n      <input type=\"number\" min=\"1\" max=\"10\" value={state2}\n        onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {\n          setState2((ev.target.value as unknown) as number);\n        }}\n      />\n      <input type=\"number\" min=\"1\" max=\"10\" value={state3}\n        onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {\n          setState3((ev.target.value as unknown) as number);\n        }}\n      />\n      {isValid !== null && <span>{isValid ? 'Valid!' : 'Invalid'}</span>}\n    </div>\n  );\n};\n```\n\n## Reference\n```ts \nconst [validity, revalidate] = useStateValidator(\n  state: any[] | { [p: string]: any } | { [p: number]: any },\n  validator: (state, setValidity?)=>[boolean|null, ...any[]],\n  initialValidity: any = [undefined]\n);\n```\n- **`state`**_`: any[] | { [p: string]: any } | { [p: number]: any }`_ can be both an array or object. It's _values_ will be used as a deps for inner `useEffect`.\n- **`validity`**_`: [boolean|null, ...any[]]`_ result of validity check. First element is strictly nullable boolean, but others can contain arbitrary data;\n- **`revalidate`**_`: ()=>void`_ runs validator once again\n- **`validator`**_`: (state, setValidity?)=>[boolean|null, ...any[]]`_ should return an array suitable for validity state described above;\n    - `states` - current states values as they've been passed to the hook;\n    - `setValidity` - if defined hook will not trigger validity change automatically. Useful for async validators;\n- `initialValidity` - validity value which set when validity is nt calculated yet;\n"
  },
  {
    "path": "docs/useNetworkState.md",
    "content": "# `useNetworkState`\n\nTracks the state of browser's network connection.\n\nAs of the standard it is not guaranteed that browser connected to the _Internet_, it only guarantees the network\nconnection.\n\n## Usage\n\n```jsx\nimport {useNetworkState} from 'react-use';\n\nconst Demo = () => {\n  const state = useNetworkState();\n\n  return (\n    <pre>\n      {JSON.stringify(state, null, 2)}\n    </pre>\n  );\n};\n```\n\n#### State interface:\n\n```typescript\ninterface IUseNetworkState {\n  /**\n   * @desc Whether browser connected to the network or not.\n   */\n  online: boolean | undefined;\n  /**\n   * @desc Previous value of `online` property. Helps to identify if browser\n   * just connected or lost connection.\n   */\n  previous: boolean | undefined;\n  /**\n   * @desc The {Date} object pointing to the moment when state change occurred.\n   */\n  since: Date | undefined;\n  /**\n   * @desc Effective bandwidth estimate in megabits per second, rounded to the\n   * nearest multiple of 25 kilobits per seconds.\n   */\n  downlink: number | undefined;\n  /**\n   * @desc Maximum downlink speed, in megabits per second (Mbps), for the\n   * underlying connection technology\n   */\n  downlinkMax: number | undefined;\n  /**\n   * @desc Effective type of the connection meaning one of 'slow-2g', '2g', '3g', or '4g'.\n   * This value is determined using a combination of recently observed round-trip time\n   * and downlink values.\n   */\n  effectiveType: 'slow-2g' | '2g' | '3g' | '4g' | undefined;\n  /**\n   * @desc Estimated effective round-trip time of the current connection, rounded\n   * to the nearest multiple of 25 milliseconds\n   */\n  rtt: number | undefined;\n  /**\n   * @desc Wheter user has set a reduced data usage option on the user agent.\n   */\n  saveData: boolen | undefined;\n  /**\n   * @desc The type of connection a device is using to communicate with the network.\n   */\n  type: 'bluetooth' | 'cellular' | 'ethernet' | 'none' | 'wifi' | 'wimax' | 'other' | 'unknown' | undefined;\n}\n```\n\n#### Call signature\n\n```typescript\nfunction useNetworkState(initialState?: IUseNetworkState | (() => IUseNetworkState)): IUseNetworkState;\n```\n"
  },
  {
    "path": "docs/useObservable.md",
    "content": "# `useObservable`\n\nReact state hook that tracks the latest value of an `Observable`.\n\n\n## Usage\n\n```jsx\nimport {useObservable} from 'react-use';\n\nconst counter$ = new BehaviorSubject(0);\nconst Demo = () => {\n  const value = useObservable(counter$, 0);\n\n  return (\n    <button onClick={() => counter$.next(value + 1)}>\n      Clicked {value} times\n    </button>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useOrientation.md",
    "content": "# `useOrientation`\n\nReact sensor hook that tracks screen orientation of user's device.\n\nReturns state in the following shape\n\n```js\n{\n  angle: 0,\n  type: 'landscape-primary'\n}\n```\n\n\n## Usage\n\n```jsx\nimport {useOrientation} from 'react-use';\n\nconst Demo = () => {\n  const state = useOrientation();\n\n  return (\n    <pre>\n      {JSON.stringify(state, null, 2)}\n    </pre>\n  );\n};\n```\n"
  },
  {
    "path": "docs/usePageLeave.md",
    "content": "# `usePageLeave`\n\nReact sensor hook that fires a callback when mouse leaves the page.\n\n## Usage\n\n```jsx\nimport {usePageLeave} from 'react-use';\n\nconst Demo = () => {\n  usePageLeave(() => console.log('Page left...'));\n\n  return null;\n};\n```\n"
  },
  {
    "path": "docs/usePermission.md",
    "content": "# `usePermission`\n\nReact side-effect hook to query permission status of browser APIs.\n\n## Usage\n\n```jsx\nimport {usePermission} from 'react-use';\n\nconst Demo = () => {\n  const state = usePermission({ name: 'microphone' });\n\n  return (\n    <pre>\n      {JSON.stringify(state, null, 2)}\n    </pre>\n  );\n};\n```\n"
  },
  {
    "path": "docs/usePinchZoom.md",
    "content": "# `usePinchZoom`\n\nReact sensor hook that tracks the changes in pointer touch events and detects value of pinch difference and tell if user is zooming in or out.\n\n## Usage\n\n```jsx\nimport { usePinchZoom } from \"react-use\";\n\nconst Demo = () => {\n  const [scale, setState] = useState(1);\n  const scaleRef = useRef();\n  const { zoomingState, pinchState } = usePinchZoom(scaleRef);\n\n  useEffect(() => {\n    if (zoomingState === \"ZOOM_IN\") {\n      // perform zoom in scaling\n      setState(scale + 0.1)\n    } else if (zoomingState === \"ZOOM_OUT\") {\n      // perform zoom out in scaling\n      setState(scale - 0.1)\n    }\n  }, [zoomingState]);\n\n  return (\n    <div ref={scaleRef}>\n      <img\n        src=\"https://www.olympus-imaging.co.in/content/000107506.jpg\"\n        style={{\n          zoom: scale,\n        }}\n      />\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/usePrevious.md",
    "content": "# `usePrevious`\n\nReact state hook that returns the previous state as described in the [React hooks FAQ](https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state).\n\n## Usage\n\n```jsx\nimport {usePrevious} from 'react-use';\n\nconst Demo = () => {\n  const [count, setCount] = React.useState(0);\n  const prevCount = usePrevious(count);\n\n  return (\n    <p>\n      <button onClick={() => setCount(count + 1)}>+</button>\n      <button onClick={() => setCount(count - 1)}>-</button>\n      <p>\n        Now: {count}, before: {prevCount}\n      </p>\n    </p>\n  );\n};\n```\n\n## Reference\n\n```ts\nconst prevState = usePrevious = <T>(state: T): T;\n```\n"
  },
  {
    "path": "docs/usePreviousDistinct.md",
    "content": "# `usePreviousDistinct`\n\nJust like `usePrevious` but it will only update once the value actually changes. This is important when other\nhooks are involved and you aren't just interested in the previous props version, but want to know the previous\ndistinct value\n\n## Usage\n\n```jsx\nimport {usePreviousDistinct, useCounter} from 'react-use';\n\nconst Demo = () => {\n  const [count, { inc: relatedInc }] = useCounter(0);\n  const [unrelatedCount, { inc }] = useCounter(0);\n  const prevCount = usePreviousDistinct(count);\n\n  return (\n    <p>\n      Now: {count}, before: {prevCount}\n      <button onClick={() => relatedInc()}>Increment</button>\n      Unrelated: {unrelatedCount}\n      <button onClick={() => inc()}>Increment Unrelated</button>\n    </p>\n  );\n};\n```\n\nYou can also provide a way of identifying the value as unique. By default, a strict equals is used.\n\n```jsx\nimport {usePreviousDistinct} from 'react-use';\n\nconst Demo = () => {\n  const [str, setStr] = React.useState(\"something_lowercase\");\n  const [unrelatedCount] = React.useState(0);\n  const prevStr = usePreviousDistinct(str, (prev, next) => (prev && prev.toUpperCase()) === next.toUpperCase());\n\n  return (\n    <p>\n      Now: {count}, before: {prevCount}\n      Unrelated: {unrelatedCount}\n    </p>\n  );\n};\n```\n\n## Reference\n\n```ts\nconst prevState = usePreviousDistinct = <T>(state: T, compare?: (prev: T | undefined, next: T) => boolean): T;\n```\n"
  },
  {
    "path": "docs/usePromise.md",
    "content": "# `usePromise`\n\nReact Lifecycle hook that returns a helper function for wrapping promises.\nPromises wrapped with this function will resolve only when component is mounted.\n\n\n## Usage\n\n```jsx\nimport {usePromise} from 'react-use';\n\nconst Demo = ({promise}) => {\n  const mounted = usePromise();\n  const [value, setValue] = useState();\n\n  useEffect(() => {\n    (async () => {\n      const value = await mounted(promise);\n      // This line will not execute if <Demo> component gets unmounted.\n      setValue(value);\n    })();\n  });\n};\n```\n"
  },
  {
    "path": "docs/useQueue.md",
    "content": "# `useQueue`\n\nReact state hook implements simple FIFO queue.\n\n\n## Usage\n\n```jsx\nimport { useQueue } from 'react-use';\n\nconst Demo = () => {\n  const { add, remove, first, last, size } = useQueue();\n\n  return (\n    <div>\n      <ul>\n        <li>first: {first}</li>\n        <li>last: {last}</li>\n        <li>size: {size}</li>\n      </ul>\n      <button onClick={() => add((last || 0) + 1)}>Add</button>\n      <button onClick={() => remove()}>Remove</button>\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useRaf.md",
    "content": "# `useRaf`\n\nReact animation hook that forces component to re-render on each `requestAnimationFrame`,\nreturns percentage of time elapsed.\n\n\n## Usage\n\n```jsx\nimport {useRaf} from 'react-use';\n\nconst Demo = () => {\n  const elapsed = useRaf(5000, 1000);\n\n  return (\n    <div>\n      Elapsed: {elapsed}\n    </div>\n  );\n};\n```\n\n\n## Reference\n\n```ts\nuseRaf(ms?: number, delay?: number): number;\n```\n\n- `ms` &mdash; milliseconds for how long to keep re-rendering component, defaults to `1e12`.\n- `delay` &mdash; delay in milliseconds after which to start re-rendering component, defaults to `0`.\n"
  },
  {
    "path": "docs/useRafLoop.md",
    "content": "# `useRafLoop`\n\nThis hook call given function within the RAF loop without re-rendering parent component.\nLoop stops automatically on component unmount.\n\nAdditionally hook provides methods to start/stop loop and check current state.\n\n## Usage\n\n```jsx\nimport * as React from 'react';\nimport { useRafLoop, useUpdate } from 'react-use';\n\nconst Demo = () => {\n  const [ticks, setTicks] = React.useState(0);\n  const [lastCall, setLastCall] = React.useState(0);\n  const update = useUpdate();\n\n  const [loopStop, loopStart, isActive] = useRafLoop((time) => {\n    setTicks(ticks => ticks + 1);\n    setLastCall(time);\n  });\n\n  return (\n    <div>\n      <div>RAF triggered: {ticks} (times)</div>\n      <div>Last high res timestamp: {lastCall}</div>\n      <br />\n      <button onClick={() => {\n        isActive() ? loopStop() : loopStart();\n        update();\n      }}>{isActive() ? 'STOP' : 'START'}</button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nconst [stopLoop, startLoop, isActive] = useRafLoop(callback: FrameRequestCallback, initiallyActive = true);\n```\n* **`callback`**_: `(time: number)=>void`_ &mdash; function to call each RAF tick.\n    * **`time`**_: `number`_ &mdash; DOMHighResTimeStamp, which indicates the current time (based on the number of milliseconds since time origin).\n* **`initiallyActive`**_: `boolean`_ &mdash; whether loop should be started at initial render.\n* Return\n    * **`stopLoop`**_: `()=>void`_ &mdash; stop loop if it is active.\n    * **`startLoop`**_: `()=>void`_ &mdash; start loop if it was inactive.\n    * **`isActive`**_: `()=>boolean`_ &mdash; _true_ if loop is active.\n\n"
  },
  {
    "path": "docs/useRafState.md",
    "content": "# `useRafState`\n\nReact state hook that only updates state in the callback of [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame).\n\n## Usage\n\n```jsx\nimport {useRafState, useMount} from 'react-use';\n\nconst Demo = () => {\n  const [state, setState] = useRafState({\n    width: 0,\n    height: 0,\n  });\n\n  useMount(() => {\n    const onResize = () => {\n      setState({\n        width: window.clientWidth,\n        height: window.height,\n      });\n    };\n\n    window.addEventListener('resize', onResize);\n\n    return () => {\n      window.removeEventListener('resize', onResize);\n    };\n  });\n\n  return <pre>{JSON.stringify(state, null, 2)}</pre>;\n};\n```\n"
  },
  {
    "path": "docs/useRendersCount.md",
    "content": "# `useRendersCount`\n\nTracks component's renders count including the first render.\n\n## Usage\n\n```typescript jsx\nimport * as React from 'react';\nimport { useRendersCount } from \"react-use\";  \n\nconst Demo = () => {\n  const update = useUpdate();\n  const rendersCount = useRendersCount();\n\n  return (\n    <div>\n      <span>Renders count: {rendersCount}</span>\n      <br />\n      <button onClick={update}>re-render</button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```typescript\nconst rendersCount: number = useRendersCount();\n```\n"
  },
  {
    "path": "docs/useScratch.md",
    "content": "# `useScratch`\n\nReact sensor hook that tracks state of mouse \"scrubs\" (or \"scratches\").\n\n## Usage\n\n```jsx\nimport useScratch from 'react-use/lib/useScratch';\n\nconst Demo = () => {\n  const [ref, state] = useScratch();\n\n  const blockStyle: React.CSSProperties = {\n    position: 'relative',\n    width: 400,\n    height: 400,\n    border: '1px solid tomato',\n  };\n\n  const preStyle: React.CSSProperties = {\n    pointerEvents: 'none',\n    userSelect: 'none',\n  };\n\n  let { x = 0, y = 0, dx = 0, dy = 0 } = state;\n  if (dx < 0) [x, dx] = [x + dx, -dx];\n  if (dy < 0) [y, dy] = [y + dy, -dy];\n\n  const rectangleStyle: React.CSSProperties = {\n    position: 'absolute',\n    left: x,\n    top: y,\n    width: dx,\n    height: dy,\n    border: '1px solid tomato',\n    pointerEvents: 'none',\n    userSelect: 'none',\n  };\n\n  return (\n    <div ref={ref} style={blockStyle}>\n      <pre style={preStyle}>{JSON.stringify(state, null, 4)}</pre>\n      {state.isScratching && <div style={rectangleStyle} />}\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nconst [ref, state] = useScratch();\n```\n\n`state` is:\n\n```ts\nexport interface ScratchSensorState {\n  isScratching: boolean;\n  start?: number;\n  end?: number;\n  x?: number;\n  y?: number;\n  dx?: number;\n  dy?: number;\n  docX?: number;\n  docY?: number;\n  posX?: number;\n  posY?: number;\n  elH?: number;\n  elW?: number;\n  elX?: number;\n  elY?: number;\n}\n```\n"
  },
  {
    "path": "docs/useScroll.md",
    "content": "# `useScroll`\n\nReact sensor hook that re-renders when the scroll position in a DOM element changes.\n\n## Usage\n\n```jsx\nimport {useScroll} from 'react-use';\n\nconst Demo = () => {\n  const scrollRef = React.useRef(null);\n  const {x, y} = useScroll(scrollRef);\n\n  return (\n    <div ref={scrollRef}>\n      <div>x: {x}</div>\n      <div>y: {y}</div>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseScroll(ref: RefObject<HTMLElement>);\n```\n"
  },
  {
    "path": "docs/useScrollbarWidth.md",
    "content": "# `useScrollbarWidth`\n\nHook that will return current browser's scrollbar width.  \nIn case hook been called before DOM ready, it will return `undefined` and will cause re-render on first available RAF.\n> **_NOTE:_** it does not work (return 0) for mobile devices, because their scrollbar width can not be determined.\n\n## Usage\n\n```jsx\nconst Demo = () => {\n  const sbw = useScrollbarWidth();\n\n  return (\n    <div>\n      {sbw === undefined ? `DOM is not ready yet, SBW detection delayed` : `Browser's scrollbar width is ${sbw}px`}\n    </div>\n  );\n};\n```\n\n## Reference\n\n```typescript\nconst sbw: number | undefined = useScrollbarWidth();\n```\n"
  },
  {
    "path": "docs/useScrolling.md",
    "content": "# `useScrolling`\n\nReact sensor hook that keeps track of whether the user is scrolling or not.\n\n## Usage\n\n```jsx\nimport { useScrolling } from \"react-use\";\n\nconst Demo = () => {\n  const scrollRef = React.useRef(null);\n  const scrolling = useScrolling(scrollRef);\n\n  return (\n    <div ref={scrollRef}>\n      {<div>{scrolling ? \"Scrolling\" : \"Not scrolling\"}</div>}\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseScrolling(ref: RefObject<HTMLElement>);\n```\n"
  },
  {
    "path": "docs/useSearchParam.md",
    "content": "# `useSearchParam`\n\nReact sensor hook that tracks browser's location search param.\n\n## Usage\n\n```jsx\nimport {useSearchParam} from 'react-use';\n\nconst Demo = () => {\n  const edit = useSearchParam('edit');\n\n  return (\n    <div>\n      <div>edit: {edit || '🤷‍♂️'}</div>\n      <div>\n        <button onClick={() => history.pushState({}, '', location.pathname + '?edit=123')}>Edit post 123 (?edit=123)</button>\n      </div>\n      <div>\n      <button onClick={() => history.pushState({}, '', location.pathname + '?edit=999')}>Edit post 999 (?edit=999)</button>\n      </div>\n      <div>\n        <button onClick={() => history.pushState({}, '', location.pathname)}>Close modal</button>\n      </div>\n    </div>\n  );\n};\n```\n\n## Caveats/Gotchas\n\nWhen using a hash router, like `react-router`'s [`<HashRouter>`](https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/api/HashRouter.md), this hook won't be able to read the search parameters as they are considered part of the hash of the URL by browsers.\n"
  },
  {
    "path": "docs/useSessionStorage.md",
    "content": "# `useSessionStorage`\n\nReact side-effect hook that manages a single `sessionStorage` key.\n\n\n## Usage\n\n```jsx\nimport {useSessionStorage} from 'react-use';\n\nconst Demo = () => {\n  const [value, setValue] = useSessionStorage('my-key', 'foo');\n\n  return (\n    <div>\n      <div>Value: {value}</div>\n      <button onClick={() => setValue('bar')}>bar</button>\n      <button onClick={() => setValue('baz')}>baz</button>\n    </div>\n  );\n};\n```\n\n\n## Reference\n\n```js\nuseSessionStorage(key);\nuseSessionStorage(key, initialValue);\nuseSessionStorage(key, initialValue, raw);\n```\n\n- `key` &mdash; `sessionStorage` key to manage.\n- `initialValue` &mdash; initial value to set, if value in `sessionStorage` is empty.\n- `raw` &mdash; boolean, if set to `true`, hook will not attempt to JSON serialize stored values.\n"
  },
  {
    "path": "docs/useSet.md",
    "content": "# `useSet`\n\nReact state hook that tracks a [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set).\n\n## Usage\n\nWhat is the difference between the \"clear()\" method and the \"reset()\" method?\n\nThe \"reset()\" method returns the \"Set\" to the initial value passed during \"useSet\nThe \"clear()\" method completely empties the \"Set\".\n\n```jsx\nimport {useSet} from 'react-use';\n\nconst Demo = () => {\n  const [set, { add, has, remove, toggle, reset, clear }] = useSet(new Set(['hello']));\n\n  return (\n    <div>\n      <button onClick={() => add(String(Date.now()))}>Add</button>\n      <button onClick={() => reset()}>Reset</button>\n      <button onClick={() => clear()}>Clear</button>\n      <button onClick={() => remove('hello')} disabled={!has('hello')}>\n        Remove 'hello'\n      </button>\n      <button onClick={() => toggle('hello')}>Toggle hello</button>\n      <pre>{JSON.stringify(Array.from(set), null, 2)}</pre>\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useSetState.md",
    "content": "# `useSetState`\n\nReact state hook that creates `setState` method which works similar to how\n`this.setState` works in class components&mdash;it merges object changes into\ncurrent state.\n\n\n## Usage\n\n```jsx\nimport {useSetState} from 'react-use';\n\nconst Demo = () => {\n  const [state, setState] = useSetState({});\n\n  return (\n    <div>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      <button onClick={() => setState({hello: 'world'})}>hello</button>\n      <button onClick={() => setState({foo: 'bar'})}>foo</button>\n      <button \n        onClick={() => {\n          setState((prevState) => ({\n            count: (prevState.count || 0) + 1,\n          }))\n        }}\n      >\n        count\n      </button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```js\nconst [state, setState] = useSetState({cnt: 0});\n\nsetState({cnt: state.cnt + 1});\nsetState((prevState) => ({\n  cnt: prevState + 1,\n}));\n```\n"
  },
  {
    "path": "docs/useShallowCompareEffect.md",
    "content": "# `useShallowCompareEffect`\n\nA modified useEffect hook that is using shallow comparison on each of its dependencies instead of reference equality.\n\n## Usage\n\n```jsx\nimport {useCounter, useShallowCompareEffect} from 'react-use';\n\nconst Demo = () => {\n  const [count, {inc: inc}] = useCounter(0);\n  const options = { step: 2 };\n\n  useShallowCompareEffect(() => {\n    inc(options.step)\n  }, [options]);\n\n  return (\n    <div>\n      <p>useShallowCompareEffect: {count}</p>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseShallowCompareEffect(effect: () => void | (() => void | undefined), deps: any[]);\n```\n"
  },
  {
    "path": "docs/useSize.md",
    "content": "# `useSize`\n\nReact sensor hook that tracks size of an HTML element.\n\n## Usage\n\n```jsx\nimport {useSize} from 'react-use';\n\nconst Demo = () => {\n  const [sized, {width, height}] = useSize(\n    ({width}) => <div style={{background: 'red'}}>Size me up! ({width}px)</div>,\n    { width: 100, height: 100 }\n  );\n\n  return (\n    <div>\n      {sized}\n      <div>width: {width}</div>\n      <div>height: {height}</div>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```js\nuseSize(element, initialSize);\n```\n\n- `element` &mdash; sized element.\n- `initialSize` &mdash; initial size containing a `width` and `height` key.\n\n## Related hooks\n\n- [useMeasure](./useMeasure.md)\n"
  },
  {
    "path": "docs/useSlider.md",
    "content": "# `useSlider`\n\nReact UI hook that provides slide behavior over any HTML element. Supports both mouse and touch events.\n\n## Usage\n\n```jsx\nimport {useSlider} from 'react-use';\n\nconst Demo = () => {\n  const ref = React.useRef(null);\n  const {isSliding, value, pos, length} = useSlider(ref);\n\n  return (\n    <div>\n      <div ref={ref} style={{ position: 'relative' }}>\n        <p style={{ textAlign: 'center', color: isSliding ? 'red' : 'green' }}>\n          {Math.round(value * 100)}%\n        </p>\n        <div style={{ position: 'absolute', left: pos }}>🎚</div>\n      </div>\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useSpeech.md",
    "content": "# `useSpeech`\n\nReact UI hook that synthesizes human voice that speaks a given string.\n\n\n## Usage\n\n```jsx\nimport {useSpeech} from 'react-use';\n\nconst voices = window.speechSynthesis.getVoices();\n\nconst Demo = () => {\n  const state = useSpeech('Hello world!', { rate: 0.8, pitch: 0.5, voice: voices[0] });\n\n  return (\n    <pre>\n      {JSON.stringify(state, null, 2)}\n    </pre>  \n  );\n};\n```\n"
  },
  {
    "path": "docs/useSpring.md",
    "content": "# `useSpring`\n\nReact animation hook that updates a single numeric value over time according\nto spring dynamics.\n\n## Usage\n\n```jsx\nimport useSpring from 'react-use/lib/useSpring';\n\nconst Demo = () => {\n  const [target, setTarget] = useState(50);\n  const value = useSpring(target);\n\n  return (\n    <div>\n      {value}\n      <br />\n      <button onClick={() => setTarget(0)}>Set 0</button>\n      <button onClick={() => setTarget(100)}>Set 100</button>\n    </div>\n  );\n};\n```\n\nNote: Because of dependency on `rebound` you have to import this hook directly like shown above.\n\n## Requirements\n\nInstall [`rebound`](https://github.com/facebook/rebound-js) peer dependency:\n\n```bash\nnpm add rebound\n# or\nyarn add rebound\n```\n\n## Reference\n\n```js\nconst currentValue = useSpring(targetValue);\nconst currentValue = useSpring(targetValue, tension, friction);\n```\n"
  },
  {
    "path": "docs/useStartTyping.md",
    "content": "# `useStartTyping`\n\nReact sensor hook that fires a callback when user starts typing. Can be used\nto focus default input field on the page.\n\n## Usage\n\n```jsx\nimport {useStartTyping} from 'react-use';\n\nconst Demo = () => {\n  useStartTyping(() => alert('Started typing...'));\n\n  return null;\n};\n```\n"
  },
  {
    "path": "docs/useStateList.md",
    "content": "# `useStateList`\n\nProvides handles for circular iteration over states list.  \nSupports forward and backward iterations and arbitrary position set.\n\n## Usage\n\n```jsx\nimport { useStateList } from 'react-use';\nimport { useRef } from 'react';\n\nconst stateSet = ['first', 'second', 'third', 'fourth', 'fifth'];\n\nconst Demo = () => {\n  const { state, prev, next, setStateAt, setState, currentIndex, isFirst, isLast } = useStateList(stateSet);\n  const indexInput = useRef<HTMLInputElement>(null);\n  const stateInput = useRef<HTMLInputElement>(null);\n\n  return (\n    <div>\n      <pre>\n        {state} [index: {currentIndex}], [isFirst: {isFirst}], [isLast: {isLast}]\n      </pre>\n      <button onClick={() => prev()}>prev</button>\n      <br />\n      <button onClick={() => next()}>next</button>\n      <br />\n      <input type=\"text\" ref={indexInput} style={{ width: 120 }} />\n      <button onClick={() => setStateAt((indexInput.current!.value as unknown) as number)}>set state by index</button>\n      <br />\n      <input type=\"text\" ref={stateInput} style={{ width: 120 }} />\n      <button onClick={() => setState(stateInput.current!.value)}> set state by value</button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nconst { state, currentIndex, prev, next, setStateAt, setState, isFirst, isLast } = useStateList<T>(stateSet: T[] = []);\n```\n\nIf `stateSet` changed, became shorter than before and `currentIndex` left in shrunk gap - the last element of list will be taken as current.\n\n- **`state`**_`: T`_ &mdash; current state value;\n- **`currentIndex`**_`: number`_ &mdash; current state index;\n- **`prev()`**_`: void`_ &mdash; switches state to the previous one. If first element selected it will switch to the last one;\n- **`next()`**_`: void`_ &mdash; switches state to the next one. If last element selected it will switch to the first one;\n- **`setStateAt(newIndex: number)`**_`: void`_ &mdash; set the arbitrary state by index. Indexes are looped, and can be negative.  \n  _4ex:_ if list contains 5 elements, attempt to set index 9 will bring use to the 5th element, in case of negative index it will start counting from the right, so -17 will bring us to the 4th element.\n- **`setState(state: T)`**_`: void`_ &mdash; set the arbitrary state value that exists in `stateSet`. _In case new state does not exists in `stateSet` an Error will be thrown._\n- **`isFirst`**_`: boolean`_ &mdash; `true` if current state is the first one.\n- **`isLast`**_`: boolean`_ &mdash; `true` if current state is the last one.\n"
  },
  {
    "path": "docs/useStateValidator.md",
    "content": "# `useStateValidator`\n\nEach time given state changes - validator function is invoked.\n\n## Usage\n```ts \nimport * as React from 'react';\nimport { useCallback } from 'react';\nimport { useStateValidator } from 'react-use';\n\nconst DemoStateValidator = s => [s === '' ? null : (s * 1) % 2 === 0];\nconst Demo = () => {\n  const [state, setState] = React.useState<string | number>(0);\n  const [[isValid]] = useStateValidator(state, DemoStateValidator);\n\n  return (\n    <div>\n      <div>Below field is valid only if number is even</div>\n      <input\n        type=\"number\"\n        min=\"0\"\n        max=\"10\"\n        value={state}\n        onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {\n          setState(ev.target.value);\n        }}\n      />\n      {isValid !== null && <span>{isValid ? 'Valid!' : 'Invalid'}</span>}\n    </div>\n  );\n};\n```\n\n## Reference\n```ts \nconst [validity, revalidate] = useStateValidator(\n  state: any,\n  validator: (state, setValidity?)=>[boolean|null, ...any[]],\n  initialValidity: any\n);\n```\n- **`validity`**_`: [boolean|null, ...any[]]`_ result of validity check. First element is strictly nullable boolean, but others can contain arbitrary data;\n- **`revalidate`**_`: ()=>void`_ runs validator once again\n- **`validator`**_`: (state, setValidity?)=>[boolean|null, ...any[]]`_ should return an array suitable for validity state described above;\n    - `state` - current state;\n    - `setValidity` - if defined hook will not trigger validity change automatically. Useful for async validators;\n- `initialValidity` - validity value which set when validity is nt calculated yet;\n"
  },
  {
    "path": "docs/useStateWithHistory.md",
    "content": "# `useStateHistory`\n\nStores defined amount of previous state values and provides handles to travel through them.\n\n## Usage\n\n## Reference\n\n```typescript\nconst [state, setState, stateHistory] = useStateWithHistory<S = undefined>(\n  initialState?: S | (()=>S),\n  capacity?: number = 10,\n  initialHistory?: S\n);\n```\n\n- **`state`**, **`setState`** and **`initialState`** are exactly the same with native React's `useState` hook;\n- **`capacity`** - amount of history entries held by storage;\n- **`initialHistory`** - if defined it will be used as initial history value, otherwise history will equal `[ initialState ]`.  \nInitial state will not be pushed to initial history.  \nIf entries amount is greater than `capacity` parameter it won't be modified on init but will be trimmed on the next call to `setState`;\n- **`stateHistory`** - an object containing history state:\n    - **`history`**_`: S[]`_ - an array holding history entries. _It will have the same ref all the time so be careful with that one!_;\n    - **`position`**_`: number`_ - current position _index_ in history;\n    - **`capacity`**_`: number = 10`_ - maximum amount of history entries;\n    - **`back`**_`: (amount?: number) => void`_ - go back in state history, it will cause `setState` to be invoked and component re-render.\n    If first element of history reached, the call will have no effect;\n    - **`forward`**_`: (amount?: number) => void`_ - go forward in state history, it will cause `setState` to be invoked and component re-render.  \n    If last element of history is reached, the call will have no effect;\n    - **`go`**_`: (position: number) => void`_ - go to arbitrary position in history.  \n    In case `position` is non-negative ot will count elements from beginning.\n    Negative `position` will cause elements counting from the end, so `go(-2)` equals `go(history.length - 1)`;\n    \n"
  },
  {
    "path": "docs/useThrottle.md",
    "content": "# `useThrottle` and `useThrottleFn`\n\nReact hooks that throttle.\n\n## Usage\n\n```jsx\nimport React, { useState } from 'react';\nimport { useThrottle, useThrottleFn } from 'react-use';\n\nconst Demo = ({value}) => {\n  const throttledValue = useThrottle(value);\n  // const throttledValue = useThrottleFn(value => value, 200, [value]);\n\n  return (\n    <>\n      <div>Value: {value}</div>\n      <div>Throttled value: {throttledValue}</div>\n    </>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseThrottle(value, ms?: number);\nuseThrottleFn(fn, ms, args);\n```\n"
  },
  {
    "path": "docs/useThrottleFn.md",
    "content": "# `useThrottleFn`\n\nReact hook that invokes a function and then delays subsequent function calls until after wait milliseconds have elapsed since the last time the throttled function was invoked.\n\nThe third argument is the array of values that the throttle depends on, in the same manner as useEffect. The throttle timeout will start when one of the values changes.\n\n## Usage\n\n```jsx\nimport React, { useState } from 'react';\nimport { useThrottleFn } from 'react-use';\n\nconst Demo = () => {\n  const [status, setStatus] = React.useState('Updating stopped');\n  const [value, setValue] = React.useState('');\n  const [throttledValue, setThrottledValue] = React.useState('');\n\n  useThrottleFn(\n    () => {\n      setStatus('Waiting for input...');\n      setThrottledValue(value);\n    },\n    2000,\n    [value]\n  );\n\n  return (\n    <div>\n      <input\n        type=\"text\"\n        value={value}\n        placeholder=\"Throttled input\"\n        onChange={({ currentTarget }) => {\n          setStatus('Updating stopped');\n          setValue(currentTarget.value);\n        }}\n      />\n      <div>{status}</div>\n      <div>Throttled value: {throttledValue}</div>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseThrottleFn(fn, ms: number, args: any[]);\n```\n"
  },
  {
    "path": "docs/useTimeout.md",
    "content": "# `useTimeout`\n\nRe-renders the component after a specified number of milliseconds.  \nProvides handles to cancel and/or reset the timeout.\n\n## Usage\n\n```jsx\nimport { useTimeout } from 'react-use';\n\nfunction TestComponent(props: { ms?: number } = {}) {\n  const ms = props.ms || 5000;\n  const [isReady, cancel] = useTimeout(ms);\n\n  return (\n    <div>\n      { isReady() ? 'I\\'m reloaded after timeout' : `I will be reloaded after ${ ms / 1000 }s` }\n      { isReady() === false ? <button onClick={ cancel }>Cancel</button> : '' }\n    </div>\n  );\n}\n\nconst Demo = () => {\n  return (\n    <div>\n      <TestComponent />\n      <TestComponent ms={ 10000 } />\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts \nconst [\n    isReady: () => boolean | null,\n    cancel: () => void,\n    reset: () => void,\n] = useTimeout(ms: number = 0);\n```\n\n- **`isReady`**_` :()=>boolean|null`_ - function returning current timeout state:\n    - `false` - pending re-render\n    - `true` - re-render performed\n    - `null` - re-render cancelled\n- **`cancel`**_` :()=>void`_ - cancel the timeout (component will not be re-rendered)\n- **`reset`**_` :()=>void`_ - reset the timeout\n"
  },
  {
    "path": "docs/useTimeoutFn.md",
    "content": "# `useTimeoutFn`\n\nCalls given function after specified amount of milliseconds.\n\nSeveral thing about it's work:\n- does not re-render component;\n- automatically cancel timeout on cancel;\n- automatically reset timeout on delay change;\n- reset function call will cancel previous timeout;\n- timeout will NOT be reset on function change. It will be called within the timeout, you have to reset it on your own when needed. \n\n## Usage\n\n```jsx\nimport * as React from 'react';\nimport { useTimeoutFn } from 'react-use';\n\nconst Demo = () => {\n  const [state, setState] = React.useState('Not called yet');\n\n  function fn() {\n    setState(`called at ${Date.now()}`);\n  }\n\n  const [isReady, cancel, reset] = useTimeoutFn(fn, 5000);\n  const cancelButtonClick = useCallback(() => {\n    if (isReady() === false) {\n      cancel();\n      setState(`cancelled`);\n    } else {\n      reset();\n      setState('Not called yet');\n    }\n  }, []);\n\n  const readyState = isReady();\n\n  return (\n    <div>\n      <div>{readyState !== null ? 'Function will be called in 5 seconds' : 'Timer cancelled'}</div>\n      <button onClick={cancelButtonClick}> {readyState === false ? 'cancel' : 'restart'} timeout</button>\n      <br />\n      <div>Function state: {readyState === false ? 'Pending' : readyState ? 'Called' : 'Cancelled'}</div>\n      <div>{state}</div>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts \nconst [\n    isReady: () => boolean | null,\n    cancel: () => void,\n    reset: () => void,\n] = useTimeoutFn(fn: Function, ms: number = 0);\n```\n\n- **`fn`**_`: Function`_ - function that will be called;\n- **`ms`**_`: number`_ - delay in milliseconds;\n- **`isReady`**_`: ()=>boolean|null`_ - function returning current timeout state:\n    - `false` - pending\n    - `true` - called\n    - `null` - cancelled\n- **`cancel`**_`: ()=>void`_ - cancel the timeout\n- **`reset`**_`: ()=>void`_ - reset the timeout\n\n"
  },
  {
    "path": "docs/useTitle.md",
    "content": "# `useTitle`\n\nReact side-effect hook that sets title of the page.\n\n\n## Usage\n\n```jsx\nimport {useTitle} from 'react-use';\n\nconst Demo = () => {\n  useTitle('Hello world!');\n\n  return null;\n};\n```\n"
  },
  {
    "path": "docs/useToggle.md",
    "content": "# `useToggle`\n\nReact state hook that tracks value of a boolean.\n\n`useBoolean` is an alias for `useToggle`.\n\n## Usage\n\n```jsx\nimport {useToggle} from 'react-use';\n\nconst Demo = () => {\n  const [on, toggle] = useToggle(true);\n\n  return (\n    <div>\n      <div>{on ? 'ON' : 'OFF'}</div>\n      <button onClick={toggle}>Toggle</button>\n      <button onClick={() => toggle(true)}>set ON</button>\n      <button onClick={() => toggle(false)}>set OFF</button>\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useTween.md",
    "content": "# `useTween`\n\nReact animation hook that tweens a number between 0 and 1.\n\n\n## Usage\n\n```jsx\nimport {useTween} from 'react-use';\n\nconst Demo = () => {\n  const t = useTween();\n\n  return (\n    <div>\n      Tween: {t}\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseTween(easing?: string, ms?: number, delay?: number): number\n```\n\nReturns a number that begins with 0 and ends with 1 when animation ends.\n\n- `easing` &mdash; one of the valid [easing names](https://github.com/streamich/ts-easing/blob/master/src/index.ts), defaults to `inCirc`.\n- `ms` &mdash; milliseconds for how long to keep re-rendering component, defaults to `200`.\n- `delay` &mdash; delay in milliseconds after which to start re-rendering component, defaults to `0`.\n"
  },
  {
    "path": "docs/useUnmount.md",
    "content": "# `useUnmount`\n\nReact lifecycle hook that calls a function when the component will unmount. Use `useLifecycles` if you need both a mount and unmount function.\n\n## Usage\n\n```jsx\nimport {useUnmount} from 'react-use';\n\nconst Demo = () => {\n  useUnmount(() => alert('UNMOUNTED'));\n  return null;\n};\n```\n\n## Reference\n\n```ts\nuseUnmount(fn: () => void | undefined);\n```\n"
  },
  {
    "path": "docs/useUnmountPromise.md",
    "content": "# `useUnmountPromise`\n\nA life-cycle hook that provides a higher order promise that does not resolve if component un-mounts.\n\n\n## Usage \n\n```ts\nimport useUnmountPromise from 'react-use/lib/useUnmountPromise';\n\nconst Demo = () => {\n  const mounted = useUnmountPromise();\n  useEffect(async () => {\n    await mounted(someFunction()); // Will not resolve if component un-mounts.\n  });\n};\n```\n\n\n## Reference\n\n```ts\nconst mounted = useUnmountPromise();\n\nmounted(promise);\nmounted(promise, onError);\n```\n\n- `onError` &mdash; if promise rejects after the component is unmounted, `onError`\n  callback is called with the error.\n"
  },
  {
    "path": "docs/useUpdate.md",
    "content": "# `useUpdate`\n\nReact utility hook that returns a function that forces component\nto re-render when called.\n\n\n## Usage\n\n```jsx\nimport {useUpdate} from 'react-use';\n\nconst Demo = () => {\n  const update = useUpdate();\n  return (\n    <>\n      <div>Time: {Date.now()}</div>\n      <button onClick={update}>Update</button>\n    </>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useUpdateEffect.md",
    "content": "# `useUpdateEffect`\n\nReact effect hook that ignores the first invocation (e.g. on mount). The signature is exactly the same as the `useEffect` hook.\n\n\n## Usage\n\n```jsx\nimport React from 'react'\nimport {useUpdateEffect} from 'react-use';\n\nconst Demo = () => {\n  const [count, setCount] = React.useState(0);\n  \n  React.useEffect(() => {\n    const interval = setInterval(() => {\n      setCount(count => count + 1)\n    }, 1000)\n    \n    return () => {\n      clearInterval(interval)\n    }\n  }, [])\n  \n  useUpdateEffect(() => {\n    console.log('count', count) // will only show 1 and beyond\n    \n    return () => { // *OPTIONAL*\n      // do something on unmount\n    }\n  }) // you can include deps array if necessary\n\n  return <div>Count: {count}</div>\n};\n```\n"
  },
  {
    "path": "docs/useUpsert.md",
    "content": "# `useUpsert`\n\n> DEPRECATED!  \n> Use `useList` hook's upsert action instead\n\nSuperset of [`useList`](./useList.md). Provides an additional method to upsert (update or insert) an element into the list.\n\n## Usage\n\n```jsx\nimport {useUpsert} from 'react-use';\n\nconst Demo = () => {\n  const comparisonFunction = (a: DemoType, b: DemoType) => {\n    return a.id === b.id;\n  };\n  const [list, { set, upsert, remove }] = useUpsert(comparisonFunction, initialItems);\n\n  return (\n    <div style={{ display: 'inline-flex', flexDirection: 'column' }}>\n      {list.map((item: DemoType, index: number) => (\n        <div key={item.id}>\n          <input value={item.text} onChange={e => upsert({ ...item, text: e.target.value })} />\n          <button onClick={() => remove(index)}>Remove</button>\n        </div>\n      ))}\n      <button onClick={() => upsert({ id: (list.length + 1).toString(), text: '' })}>Add item</button>\n      <button onClick={() => set([])}>Reset</button>\n    </div>\n  );\n};\n```\n\n## Related hooks\n\n- [useList](./useList.md)\n"
  },
  {
    "path": "docs/useVibrate.md",
    "content": "# `useVibrate`\n\nReact UI hook to provide physical feedback with device vibration hardware using the [Vibration API](https://developer.mozilla.org/en-US/docs/Web/API/Vibration_API).\n\n## Usage\n\n```jsx\nimport {useVibrate} from 'react-use';\n\nconst Demo = () => {\n  const [vibrating, toggleVibrating] = useToggle(false);\n\n  useVibrate(vibrating, [300, 100, 200, 100, 1000, 300], false);\n\n  return (\n    <div>\n      <button onClick={toggleVibrating}>{vibrating ? 'Stop' : 'Vibrate'}</button>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```ts\nuseVibrate(\n  enabled: boolean = true,\n  pattern: number | number[] = [1000, 1000],\n  loop: boolean = true\n): void;\n```\n"
  },
  {
    "path": "docs/useVideo.md",
    "content": "# `useVideo`\n\nCreates `<video>` element, tracks its state and exposes playback controls.\n\n\n## Usage\n\n```jsx\nimport {useVideo} from 'react-use';\n\nconst Demo = () => {\n  const [video, state, controls, ref] = useVideo(\n    <video src=\"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4\" autoPlay />\n  );\n\n  return (\n    <div>\n      {video}\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      <button onClick={controls.pause}>Pause</button>\n      <button onClick={controls.play}>Play</button>\n      <br/>\n      <button onClick={controls.mute}>Mute</button>\n      <button onClick={controls.unmute}>Un-mute</button>\n      <br/>\n      <button onClick={() => controls.volume(.1)}>Volume: 10%</button>\n      <button onClick={() => controls.volume(.5)}>Volume: 50%</button>\n      <button onClick={() => controls.volume(1)}>Volume: 100%</button>\n      <br/>\n      <button onClick={() => controls.seek(state.time - 5)}>-5 sec</button>\n      <button onClick={() => controls.seek(state.time + 5)}>+5 sec</button>\n    </div>\n  );\n};\n```\n\n\n## Reference\n\n```jsx\nconst [video, state, controls, ref] = useVideo(props);\nconst [video, state, controls, ref] = useVideo(<video {...props}/>);\n```\n\n`video` is React's `<video>` element that you have to insert somewhere in your\nrender tree, for example:\n\n```jsx\n<div>{video}</div>\n```\n\n`state` tracks the state of the video and has the following shape:\n\n```json\n{\n  \"buffered\": [\n    {\n      \"start\": 0,\n      \"end\": 425.952625\n    }\n  ],\n  \"time\": 5.244996,\n  \"duration\": 425.952625,\n  \"paused\": false,\n  \"muted\": false,\n  \"volume\": 1\n}\n```\n\n`controls` is a list collection of methods that allow you to control the\nplayback of the video, it has the following interface:\n\n```ts\ninterface AudioControls {\n  play: () => Promise<void> | void;\n  pause: () => void;\n  mute: () => void;\n  unmute: () => void;\n  volume: (volume: number) => void;\n  seek: (time: number) => void;\n}\n```\n\n`ref` is a React reference to HTML `<video>` element, you can access the element by\n`ref.current`, note that it may be `null`.\n\nAnd finally, `props` &mdash; all props that `<video>` accepts."
  },
  {
    "path": "docs/useWindowScroll.md",
    "content": "# `useWindowScroll`\n\nReact sensor hook that re-renders on window scroll.\n\n## Usage\n\n```jsx\nimport {useWindowScroll} from 'react-use';\n\nconst Demo = () => {\n  const {x, y} = useWindowScroll();\n\n  return (\n    <div>\n      <div>x: {x}</div>\n      <div>y: {y}</div>\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/useWindowSize.md",
    "content": "# `useWindowSize`\n\nReact sensor hook that tracks dimensions of the browser window.\n\n\n## Usage\n\n```jsx\nimport {useWindowSize} from 'react-use';\n\nconst Demo = () => {\n  const {width, height} = useWindowSize();\n\n  return (\n    <div>\n      <div>width: {width}</div>\n      <div>height: {height}</div>\n    </div>\n  );\n};\n```\n\n## Reference\n\n```js\nuseWindowSize(options);\n```\n\n- `initialWidth` — Initial width value for non-browser environments.\n- `initialHeight` — Initial height value for non-browser environments.\n- `onChange` — Callback function triggered when the window size changes.\n\n## Related hooks\n\n- [useSize](./useSize.md)\n- [useMeasure](./useMeasure.md)"
  },
  {
    "path": "jest.config.base.ts",
    "content": "import type { Config } from '@jest/types';\n\nexport const baseJestConfig: Config.InitialOptions = {\n  'preset': 'ts-jest',\n  'clearMocks': true,\n  'coverageDirectory': 'coverage',\n  'testMatch': [\n    '<rootDir>/tests/**/*.test.(ts|tsx)'\n  ],\n  'setupFiles': [\n    '<rootDir>/tests/setupTests.ts'\n  ]\n}\n"
  },
  {
    "path": "jest.config.node.ts",
    "content": "import type { Config } from '@jest/types';\nimport { baseJestConfig } from './jest.config.base';\n\nconst config: Config.InitialOptions = {\n  ...baseJestConfig,\n  testEnvironment: 'node', // browser-like\n}\n\nexport default config;\n"
  },
  {
    "path": "jest.config.ts",
    "content": "import type { Config } from '@jest/types';\nimport { baseJestConfig } from './jest.config.base';\n\nconst config: Config.InitialOptions = {\n  ...baseJestConfig,\n  testEnvironment: 'jsdom', // browser-like\n}\n\nexport default config;\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-use\",\n  \"version\": \"17.6.0\",\n  \"description\": \"Collection of React Hooks\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"esm/index.js\",\n  \"sideEffects\": false,\n  \"files\": [\n    \"lib/\",\n    \"esm/\"\n  ],\n  \"types\": \"lib/index.d.ts\",\n  \"typings\": \"lib/index.d.ts\",\n  \"scripts\": {\n    \"start\": \"yarn storybook\",\n    \"test\": \"jest --maxWorkers 2\",\n    \"test:ssr\": \"jest --maxWorkers 2 --config ./jest.config.node.ts\",\n    \"test:watch\": \"jest --watch\",\n    \"test:coverage\": \"jest --coverage\",\n    \"lint\": \"eslint \\\"{src,tests,stories}/**/*.{ts,tsx}\\\"\",\n    \"lint:fix\": \"yarn lint --fix\",\n    \"lint:types\": \"tsc --noEmit\",\n    \"build:cjs\": \"tsc\",\n    \"build:es\": \"tsc -m esNext --outDir esm\",\n    \"build\": \"yarn build:cjs && yarn build:es\",\n    \"clean\": \"rimraf lib storybook-static esm\",\n    \"storybook\": \"start-storybook -p 6008\",\n    \"storybook:build\": \"build-storybook\",\n    \"storybook:upload\": \"gh-pages -d storybook-static --git \\\"$(which git)\\\"\",\n    \"storybook:clean\": \"rimraf storybook-static\",\n    \"release\": \"semantic-release\"\n  },\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"lint-staged\",\n      \"pre-push\": \"yarn lint && yarn clean && yarn build && yarn test\"\n    }\n  },\n  \"author\": \"@streamich\",\n  \"license\": \"Unlicense\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/streamich/react-use\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/streamich/react-use/issues\"\n  },\n  \"homepage\": \"https://github.com/streamich/react-use#readme\",\n  \"dependencies\": {\n    \"@types/js-cookie\": \"^2.2.6\",\n    \"@xobotyi/scrollbar-width\": \"^1.9.5\",\n    \"copy-to-clipboard\": \"^3.3.1\",\n    \"fast-deep-equal\": \"^3.1.3\",\n    \"fast-shallow-equal\": \"^1.0.0\",\n    \"js-cookie\": \"^2.2.1\",\n    \"nano-css\": \"^5.6.2\",\n    \"react-universal-interface\": \"^0.6.2\",\n    \"resize-observer-polyfill\": \"^1.5.1\",\n    \"screenfull\": \"^5.1.0\",\n    \"set-harmonic-interval\": \"^1.0.1\",\n    \"throttle-debounce\": \"^3.0.1\",\n    \"ts-easing\": \"^0.2.0\",\n    \"tslib\": \"^2.1.0\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"*\",\n    \"react-dom\": \"*\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"7.28.3\",\n    \"@babel/plugin-syntax-dynamic-import\": \"7.8.3\",\n    \"@babel/preset-env\": \"7.28.3\",\n    \"@babel/preset-react\": \"7.27.1\",\n    \"@babel/preset-typescript\": \"7.27.1\",\n    \"@semantic-release/changelog\": \"6.0.3\",\n    \"@semantic-release/git\": \"10.0.1\",\n    \"@semantic-release/npm\": \"12.0.2\",\n    \"@shopify/jest-dom-mocks\": \"2.11.7\",\n    \"@storybook/addon-actions\": \"6.4.9\",\n    \"@storybook/addon-knobs\": \"6.4.0\",\n    \"@storybook/addon-notes\": \"5.3.21\",\n    \"@storybook/addon-options\": \"5.3.21\",\n    \"@storybook/react\": \"6.4.9\",\n    \"@testing-library/react\": \"12.1.5\",\n    \"@testing-library/react-hooks\": \"7.0.2\",\n    \"@types/jest\": \"27.5.2\",\n    \"@types/react\": \"17.0.0\",\n    \"@typescript-eslint/eslint-plugin\": \"5.62.0\",\n    \"@typescript-eslint/parser\": \"5.62.0\",\n    \"babel-core\": \"6.26.3\",\n    \"babel-eslint\": \"10.1.0\",\n    \"babel-loader\": \"8.4.1\",\n    \"babel-plugin-dynamic-import-node\": \"2.3.3\",\n    \"eslint\": \"8.57.1\",\n    \"eslint-config-prettier\": \"8.10.2\",\n    \"eslint-config-react-app\": \"6.0.0\",\n    \"eslint-plugin-flowtype\": \"8.0.3\",\n    \"eslint-plugin-import\": \"2.32.0\",\n    \"eslint-plugin-jsx-a11y\": \"6.10.2\",\n    \"eslint-plugin-prettier\": \"4.2.5\",\n    \"eslint-plugin-react\": \"7.37.5\",\n    \"eslint-plugin-react-hooks\": \"4.6.0\",\n    \"fork-ts-checker-webpack-plugin\": \"6.5.3\",\n    \"gh-pages\": \"5.0.0\",\n    \"husky\": \"7.0.4\",\n    \"jest\": \"26.6.3\",\n    \"jest-localstorage-mock\": \"2.4.26\",\n    \"keyboardjs\": \"2.7.0\",\n    \"lint-staged\": \"12.5.0\",\n    \"markdown-loader\": \"6.0.0\",\n    \"prettier\": \"2.3.0\",\n    \"raf-stub\": \"3.0.0\",\n    \"react\": \"17.0.2\",\n    \"react-dom\": \"17.0.2\",\n    \"react-frame-component\": \"5.2.7\",\n    \"react-spring\": \"9.7.5\",\n    \"react-test-renderer\": \"17.0.2\",\n    \"rebound\": \"0.1.0\",\n    \"redux-logger\": \"3.0.6\",\n    \"redux-thunk\": \"2.4.2\",\n    \"rimraf\": \"3.0.2\",\n    \"rxjs\": \"7.8.2\",\n    \"semantic-release\": \"24.2.7\",\n    \"ts-jest\": \"26.5.6\",\n    \"ts-loader\": \"8.4.0\",\n    \"ts-node\": \"10.9.2\",\n    \"typescript\": \"4.1.5\"\n  },\n  \"config\": {\n    \"commitizen\": {\n      \"path\": \"git-cz\"\n    }\n  },\n  \"release\": {\n    \"branches\": [\n      \"master\",\n      {\n        \"name\": \"next\",\n        \"prerelease\": \"rc\"\n      }\n    ],\n    \"verifyConditions\": [\n      \"@semantic-release/changelog\",\n      \"@semantic-release/npm\",\n      \"@semantic-release/git\"\n    ],\n    \"prepare\": [\n      \"@semantic-release/changelog\",\n      \"@semantic-release/npm\",\n      \"@semantic-release/git\"\n    ]\n  },\n  \"lint-staged\": {\n    \"src/**/**/*.{ts,tsx}\": [\n      \"eslint --fix\",\n      \"git add\"\n    ]\n  },\n  \"volta\": {\n    \"node\": \"14.21.3\",\n    \"yarn\": \"1.22.22\"\n  },\n  \"collective\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/react-use\"\n  }\n}\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"extends\": [\n    \"config:base\"\n  ],\n  \"automerge\": true,\n  \"pinVersions\": false,\n  \"ignoreUnstable\": true,\n  \"major\": {\n    \"automerge\": false\n  },\n  \"devDependencies\": {\n    \"automerge\": true,\n    \"pinVersions\": true\n  }\n}\n"
  },
  {
    "path": "src/component/UseKey.tsx",
    "content": "import useKey from '../useKey';\nimport createRenderProp from '../factory/createRenderProp';\n\nconst UseKey = createRenderProp(useKey, ({ filter, fn, deps, ...rest }) => [\n  filter,\n  fn,\n  rest,\n  deps,\n]);\n\nexport default UseKey;\n"
  },
  {
    "path": "src/factory/createBreakpoint.ts",
    "content": "import { useEffect, useMemo, useState } from 'react';\nimport { isBrowser, off, on } from '../misc/util';\n\nconst createBreakpoint =\n  (breakpoints: { [name: string]: number } = { laptopL: 1440, laptop: 1024, tablet: 768 }) =>\n  () => {\n    const [screen, setScreen] = useState(isBrowser ? window.innerWidth : 0);\n\n    useEffect(() => {\n      const setSideScreen = (): void => {\n        setScreen(window.innerWidth);\n      };\n      setSideScreen();\n      on(window, 'resize', setSideScreen);\n      return () => {\n        off(window, 'resize', setSideScreen);\n      };\n    });\n    const sortedBreakpoints = useMemo(\n      () => Object.entries(breakpoints).sort((a, b) => (a[1] >= b[1] ? 1 : -1)),\n      [breakpoints]\n    );\n    const result = sortedBreakpoints.reduce((acc, [name, width]) => {\n      if (screen >= width) {\n        return name;\n      } else {\n        return acc;\n      }\n    }, sortedBreakpoints[0][0]);\n    return result;\n  };\n\nexport default createBreakpoint;\n"
  },
  {
    "path": "src/factory/createGlobalState.ts",
    "content": "import { useState } from 'react';\nimport { IHookStateInitAction, IHookStateSetAction, resolveHookState } from '../misc/hookState';\nimport useEffectOnce from '../useEffectOnce';\nimport useIsomorphicLayoutEffect from '../useIsomorphicLayoutEffect';\n\nexport function createGlobalState<S = any>(\n  initialState: IHookStateInitAction<S>\n): () => [S, (state: IHookStateSetAction<S>) => void];\nexport function createGlobalState<S = undefined>(): () => [\n  S,\n  (state: IHookStateSetAction<S>) => void\n];\n\nexport function createGlobalState<S>(initialState?: S) {\n  const store: {\n    state: S;\n    setState: (state: IHookStateSetAction<S>) => void;\n    setters: any[];\n  } = {\n    state: initialState instanceof Function ? initialState() : initialState,\n    setState(nextState: IHookStateSetAction<S>) {\n      store.state = resolveHookState(nextState, store.state);\n      store.setters.forEach((setter) => setter(store.state));\n    },\n    setters: [],\n  };\n\n  return () => {\n    const [globalState, stateSetter] = useState<S | undefined>(store.state);\n\n    useEffectOnce(() => () => {\n      store.setters = store.setters.filter((setter) => setter !== stateSetter);\n    });\n\n    useIsomorphicLayoutEffect(() => {\n      if (!store.setters.includes(stateSetter)) {\n        store.setters.push(stateSetter);\n      }\n    });\n\n    return [globalState, store.setState];\n  };\n}\n\nexport default createGlobalState;\n"
  },
  {
    "path": "src/factory/createHTMLMediaHook.ts",
    "content": "import * as React from 'react';\nimport { useEffect, useRef } from 'react';\nimport useSetState from '../useSetState';\nimport parseTimeRanges from '../misc/parseTimeRanges';\n\nexport interface HTMLMediaProps\n  extends React.AudioHTMLAttributes<any>,\n    React.VideoHTMLAttributes<any> {\n  src: string;\n}\n\nexport interface HTMLMediaState {\n  buffered: any[];\n  duration: number;\n  paused: boolean;\n  muted: boolean;\n  time: number;\n  volume: number;\n  playing: boolean;\n}\n\nexport interface HTMLMediaControls {\n  play: () => Promise<void> | void;\n  pause: () => void;\n  mute: () => void;\n  unmute: () => void;\n  volume: (volume: number) => void;\n  seek: (time: number) => void;\n}\n\ntype MediaPropsWithRef<T> = HTMLMediaProps & { ref?: React.MutableRefObject<T | null> };\n\nexport default function createHTMLMediaHook<T extends HTMLAudioElement | HTMLVideoElement>(\n  tag: 'audio' | 'video'\n) {\n  return (elOrProps: HTMLMediaProps | React.ReactElement<HTMLMediaProps>) => {\n    let element: React.ReactElement<MediaPropsWithRef<T>> | undefined;\n    let props: MediaPropsWithRef<T>;\n\n    if (React.isValidElement(elOrProps)) {\n      element = elOrProps;\n      props = element.props;\n    } else {\n      props = elOrProps;\n    }\n\n    const [state, setState] = useSetState<HTMLMediaState>({\n      buffered: [],\n      time: 0,\n      duration: 0,\n      paused: true,\n      muted: false,\n      volume: 1,\n      playing: false,\n    });\n    const ref = useRef<T | null>(null);\n\n    const wrapEvent = (userEvent, proxyEvent?) => {\n      return (event) => {\n        try {\n          proxyEvent && proxyEvent(event);\n        } finally {\n          userEvent && userEvent(event);\n        }\n      };\n    };\n\n    const onPlay = () => setState({ paused: false });\n    const onPlaying = () => setState({ playing: true });\n    const onWaiting = () => setState({ playing: false });\n    const onPause = () => setState({ paused: true, playing: false });\n    const onVolumeChange = () => {\n      const el = ref.current;\n      if (!el) {\n        return;\n      }\n      setState({\n        muted: el.muted,\n        volume: el.volume,\n      });\n    };\n    const onDurationChange = () => {\n      const el = ref.current;\n      if (!el) {\n        return;\n      }\n      const { duration, buffered } = el;\n      setState({\n        duration,\n        buffered: parseTimeRanges(buffered),\n      });\n    };\n    const onTimeUpdate = () => {\n      const el = ref.current;\n      if (!el) {\n        return;\n      }\n      setState({ time: el.currentTime });\n    };\n    const onProgress = () => {\n      const el = ref.current;\n      if (!el) {\n        return;\n      }\n      setState({ buffered: parseTimeRanges(el.buffered) });\n    };\n\n    if (element) {\n      element = React.cloneElement(element, {\n        controls: false,\n        ...props,\n        ref,\n        onPlay: wrapEvent(props.onPlay, onPlay),\n        onPlaying: wrapEvent(props.onPlaying, onPlaying),\n        onWaiting: wrapEvent(props.onWaiting, onWaiting),\n        onPause: wrapEvent(props.onPause, onPause),\n        onVolumeChange: wrapEvent(props.onVolumeChange, onVolumeChange),\n        onDurationChange: wrapEvent(props.onDurationChange, onDurationChange),\n        onTimeUpdate: wrapEvent(props.onTimeUpdate, onTimeUpdate),\n        onProgress: wrapEvent(props.onProgress, onProgress),\n      });\n    } else {\n      element = React.createElement(tag, {\n        controls: false,\n        ...props,\n        ref,\n        onPlay: wrapEvent(props.onPlay, onPlay),\n        onPlaying: wrapEvent(props.onPlaying, onPlaying),\n        onWaiting: wrapEvent(props.onWaiting, onWaiting),\n        onPause: wrapEvent(props.onPause, onPause),\n        onVolumeChange: wrapEvent(props.onVolumeChange, onVolumeChange),\n        onDurationChange: wrapEvent(props.onDurationChange, onDurationChange),\n        onTimeUpdate: wrapEvent(props.onTimeUpdate, onTimeUpdate),\n        onProgress: wrapEvent(props.onProgress, onProgress),\n      } as any); // TODO: fix this typing.\n    }\n\n    // Some browsers return `Promise` on `.play()` and may throw errors\n    // if one tries to execute another `.play()` or `.pause()` while that\n    // promise is resolving. So we prevent that with this lock.\n    // See: https://bugs.chromium.org/p/chromium/issues/detail?id=593273\n    let lockPlay: boolean = false;\n\n    const controls = {\n      play: () => {\n        const el = ref.current;\n        if (!el) {\n          return undefined;\n        }\n\n        if (!lockPlay) {\n          const promise = el.play();\n          const isPromise = typeof promise === 'object';\n\n          if (isPromise) {\n            lockPlay = true;\n            const resetLock = () => {\n              lockPlay = false;\n            };\n            promise.then(resetLock, resetLock);\n          }\n\n          return promise;\n        }\n        return undefined;\n      },\n      pause: () => {\n        const el = ref.current;\n        if (el && !lockPlay) {\n          return el.pause();\n        }\n      },\n      seek: (time: number) => {\n        const el = ref.current;\n        if (!el || state.duration === undefined) {\n          return;\n        }\n        time = Math.min(state.duration, Math.max(0, time));\n        el.currentTime = time;\n      },\n      volume: (volume: number) => {\n        const el = ref.current;\n        if (!el) {\n          return;\n        }\n        volume = Math.min(1, Math.max(0, volume));\n        el.volume = volume;\n        setState({ volume });\n      },\n      mute: () => {\n        const el = ref.current;\n        if (!el) {\n          return;\n        }\n        el.muted = true;\n      },\n      unmute: () => {\n        const el = ref.current;\n        if (!el) {\n          return;\n        }\n        el.muted = false;\n      },\n    };\n\n    useEffect(() => {\n      const el = ref.current!;\n\n      if (!el) {\n        if (process.env.NODE_ENV !== 'production') {\n          if (tag === 'audio') {\n            console.error(\n              'useAudio() ref to <audio> element is empty at mount. ' +\n                'It seem you have not rendered the audio element, which it ' +\n                'returns as the first argument const [audio] = useAudio(...).'\n            );\n          } else if (tag === 'video') {\n            console.error(\n              'useVideo() ref to <video> element is empty at mount. ' +\n                'It seem you have not rendered the video element, which it ' +\n                'returns as the first argument const [video] = useVideo(...).'\n            );\n          }\n        }\n        return;\n      }\n\n      setState({\n        volume: el.volume,\n        muted: el.muted,\n        paused: el.paused,\n      });\n\n      // Start media, if autoPlay requested.\n      if (props.autoPlay && el.paused) {\n        controls.play();\n      }\n    }, [props.src]);\n\n    return [element, state, controls, ref] as const;\n  };\n}\n"
  },
  {
    "path": "src/factory/createMemo.ts",
    "content": "import { useMemo } from 'react';\n\nconst createMemo =\n  <T extends (...args: any) => any>(fn: T) =>\n  (...args: Parameters<T>) =>\n    useMemo<ReturnType<T>>(() => fn(...args), args);\n\nexport default createMemo;\n"
  },
  {
    "path": "src/factory/createReducer.ts",
    "content": "import { MutableRefObject, useCallback, useRef, useState } from 'react';\nimport useUpdateEffect from '../useUpdateEffect';\n\ntype Dispatch<Action> = (action: Action) => void;\n\ninterface Store<Action, State> {\n  getState: () => State;\n  dispatch: Dispatch<Action>;\n}\n\ntype Middleware<Action, State> = (\n  store: Store<Action, State>\n) => (next: Dispatch<Action>) => (action: Action) => void;\n\nfunction composeMiddleware<Action, State>(chain: Middleware<Action, State>[]) {\n  return (context: Store<Action, State>, dispatch: Dispatch<Action>) => {\n    return chain.reduceRight((res, middleware) => {\n      return middleware(context)(res);\n    }, dispatch);\n  };\n}\n\nconst createReducer = <Action, State>(...middlewares: Middleware<Action, State>[]) => {\n  const composedMiddleware = composeMiddleware<Action, State>(middlewares);\n\n  return (\n    reducer: (state: State, action: Action) => State,\n    initialState: State,\n    initializer = (value: State) => value\n  ): [State, Dispatch<Action>] => {\n    const ref = useRef(initializer(initialState));\n    const [, setState] = useState(ref.current);\n\n    const dispatch = useCallback(\n      (action) => {\n        ref.current = reducer(ref.current, action);\n        setState(ref.current);\n        return action;\n      },\n      [reducer]\n    );\n\n    const dispatchRef: MutableRefObject<Dispatch<Action>> = useRef(\n      composedMiddleware(\n        {\n          getState: () => ref.current,\n          dispatch: (...args: [Action]) => dispatchRef.current(...args),\n        },\n        dispatch\n      )\n    );\n\n    useUpdateEffect(() => {\n      dispatchRef.current = composedMiddleware(\n        {\n          getState: () => ref.current,\n          dispatch: (...args: [Action]) => dispatchRef.current(...args),\n        },\n        dispatch\n      );\n    }, [dispatch]);\n\n    return [ref.current, dispatchRef.current];\n  };\n};\n\nexport default createReducer;\n"
  },
  {
    "path": "src/factory/createReducerContext.ts",
    "content": "import { createContext, createElement, useContext, useReducer } from 'react';\n\nconst createReducerContext = <R extends React.Reducer<any, any>>(\n  reducer: R,\n  defaultInitialState: React.ReducerState<R>\n) => {\n  const context =\n    createContext<[React.ReducerState<R>, React.Dispatch<React.ReducerAction<R>>] | undefined>(\n      undefined\n    );\n  const providerFactory = (props, children) => createElement(context.Provider, props, children);\n\n  const ReducerProvider = ({\n    children,\n    initialState,\n  }: {\n    children?: React.ReactNode;\n    initialState?: React.ReducerState<R>;\n  }) => {\n    const state = useReducer<R>(\n      reducer,\n      initialState !== undefined ? initialState : defaultInitialState\n    );\n    return providerFactory({ value: state }, children);\n  };\n\n  const useReducerContext = () => {\n    const state = useContext(context);\n    if (state == null) {\n      throw new Error(`useReducerContext must be used inside a ReducerProvider.`);\n    }\n    return state;\n  };\n\n  return [useReducerContext, ReducerProvider, context] as const;\n};\n\nexport default createReducerContext;\n"
  },
  {
    "path": "src/factory/createRenderProp.ts",
    "content": "const defaultMapPropsToArgs = (props) => [props];\n\nexport default function createRenderProp(hook, mapPropsToArgs = defaultMapPropsToArgs) {\n  return function RenderProp(props) {\n    const state = hook(...mapPropsToArgs(props));\n    const { children, render = children } = props;\n    return render ? render(state) || null : null;\n  };\n}\n"
  },
  {
    "path": "src/factory/createRouter.ts",
    "content": "import React from 'react';\n\nexport interface RouterProviderProps {\n  route: string;\n  fullRoute?: string;\n  parent?: any;\n}\n\nconst createRouter = () => {\n  const context = React.createContext<RouterProviderProps>({\n    route: '',\n  });\n\n  // not sure if this supposed to be unused, ignoring ts error for now\n  // @ts-ignore\n  const Router: React.SFC<RouterProviderProps> = (props) => {\n    const { route, fullRoute, parent, children } = props;\n\n    if (process.env.NODE_ENV !== 'production') {\n      if (typeof route !== 'string') {\n        throw new TypeError('Router route must be a string.');\n      }\n    }\n\n    return React.createElement(context.Provider as any, {\n      value: {\n        fullRoute: fullRoute || route,\n        route,\n        parent,\n      },\n      children,\n    });\n  };\n};\n\nexport default createRouter;\n"
  },
  {
    "path": "src/factory/createStateContext.ts",
    "content": "import { createContext, createElement, useContext, useState } from 'react';\n\nconst createStateContext = <T>(defaultInitialValue: T) => {\n  const context =\n    createContext<[T, React.Dispatch<React.SetStateAction<T>>] | undefined>(undefined);\n  const providerFactory = (props, children) => createElement(context.Provider, props, children);\n\n  const StateProvider = ({\n    children,\n    initialValue,\n  }: {\n    children?: React.ReactNode;\n    initialValue?: T;\n  }) => {\n    const state = useState<T>(initialValue !== undefined ? initialValue : defaultInitialValue);\n    return providerFactory({ value: state }, children);\n  };\n\n  const useStateContext = () => {\n    const state = useContext(context);\n    if (state == null) {\n      throw new Error(`useStateContext must be used inside a StateProvider.`);\n    }\n    return state;\n  };\n\n  return [useStateContext, StateProvider, context] as const;\n};\n\nexport default createStateContext;\n"
  },
  {
    "path": "src/index.ts",
    "content": "export { default as createMemo } from './factory/createMemo';\nexport { default as createReducerContext } from './factory/createReducerContext';\nexport { default as createReducer } from './factory/createReducer';\nexport { default as createStateContext } from './factory/createStateContext';\nexport { default as useAsync } from './useAsync';\nexport { default as useAsyncFn } from './useAsyncFn';\nexport { default as useAsyncRetry } from './useAsyncRetry';\nexport { default as useAudio } from './useAudio';\nexport { default as useBattery } from './useBattery';\nexport { default as useBeforeUnload } from './useBeforeUnload';\nexport { default as useBoolean } from './useBoolean';\nexport { default as useClickAway } from './useClickAway';\nexport { default as useCookie } from './useCookie';\nexport { default as useCopyToClipboard } from './useCopyToClipboard';\nexport { default as useCounter } from './useCounter';\nexport { default as useCss } from './useCss';\nexport { default as useCustomCompareEffect } from './useCustomCompareEffect';\nexport { default as useDebounce } from './useDebounce';\nexport { default as useDeepCompareEffect } from './useDeepCompareEffect';\nexport { default as useDefault } from './useDefault';\nexport { default as useDrop } from './useDrop';\nexport { default as useDropArea } from './useDropArea';\nexport { default as useEffectOnce } from './useEffectOnce';\nexport { default as useEnsuredForwardedRef, ensuredForwardRef } from './useEnsuredForwardedRef';\nexport { default as useEvent } from './useEvent';\nexport { default as useError } from './useError';\nexport { default as useFavicon } from './useFavicon';\nexport { default as useFullscreen } from './useFullscreen';\nexport { default as useGeolocation } from './useGeolocation';\nexport { default as useGetSet } from './useGetSet';\nexport { default as useGetSetState } from './useGetSetState';\nexport { default as useHarmonicIntervalFn } from './useHarmonicIntervalFn';\nexport { default as useHover } from './useHover';\nexport { default as useHoverDirty } from './useHoverDirty';\nexport { default as useIdle } from './useIdle';\nexport { default as useIntersection } from './useIntersection';\nexport { default as useInterval } from './useInterval';\nexport { default as useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';\nexport { default as useKey } from './useKey';\nexport { default as createBreakpoint } from './factory/createBreakpoint';\n// not exported because of peer dependency\n// export { default as useKeyboardJs } from './useKeyboardJs';\nexport { default as useKeyPress } from './useKeyPress';\nexport { default as useKeyPressEvent } from './useKeyPressEvent';\nexport { default as useLatest } from './useLatest';\nexport { default as useLifecycles } from './useLifecycles';\nexport { default as useList } from './useList';\nexport { default as useLocalStorage } from './useLocalStorage';\nexport { default as useLocation } from './useLocation';\nexport { default as useLockBodyScroll } from './useLockBodyScroll';\nexport { default as useLogger } from './useLogger';\nexport { default as useLongPress } from './useLongPress';\nexport { default as useMap } from './useMap';\nexport { default as useMedia } from './useMedia';\nexport { default as useMediaDevices } from './useMediaDevices';\nexport { useMediatedState } from './useMediatedState';\nexport { default as useMethods } from './useMethods';\nexport { default as useMotion } from './useMotion';\nexport { default as useMount } from './useMount';\nexport { default as useMountedState } from './useMountedState';\nexport { default as useMouse } from './useMouse';\nexport { default as useMouseHovered } from './useMouseHovered';\nexport { default as useMouseWheel } from './useMouseWheel';\nexport { default as useNetworkState } from './useNetworkState';\nexport { default as useNumber } from './useNumber';\nexport { default as useObservable } from './useObservable';\nexport { default as useOrientation } from './useOrientation';\nexport { default as usePageLeave } from './usePageLeave';\nexport { default as usePermission } from './usePermission';\nexport { default as usePrevious } from './usePrevious';\nexport { default as usePreviousDistinct } from './usePreviousDistinct';\nexport { default as usePromise } from './usePromise';\nexport { default as useQueue } from './useQueue';\nexport { default as useRaf } from './useRaf';\nexport { default as useRafLoop } from './useRafLoop';\nexport { default as useRafState } from './useRafState';\nexport { default as useSearchParam } from './useSearchParam';\nexport { default as useScratch } from './useScratch';\nexport { default as useScroll } from './useScroll';\nexport { default as useScrolling } from './useScrolling';\nexport { default as useSessionStorage } from './useSessionStorage';\nexport { default as useSetState } from './useSetState';\nexport { default as useShallowCompareEffect } from './useShallowCompareEffect';\nexport { default as useSize } from './useSize';\nexport { default as useSlider } from './useSlider';\nexport { default as useSpeech } from './useSpeech';\n// not exported because of peer dependency\n// export { default as useSpring } from './useSpring';\nexport { default as useStartTyping } from './useStartTyping';\nexport { useStateWithHistory } from './useStateWithHistory';\nexport { default as useStateList } from './useStateList';\nexport { default as useThrottle } from './useThrottle';\nexport { default as useThrottleFn } from './useThrottleFn';\nexport { default as useTimeout } from './useTimeout';\nexport { default as useTimeoutFn } from './useTimeoutFn';\nexport { default as useTitle } from './useTitle';\nexport { default as useToggle } from './useToggle';\nexport { default as useTween } from './useTween';\nexport { default as useUnmount } from './useUnmount';\nexport { default as useUnmountPromise } from './useUnmountPromise';\nexport { default as useUpdate } from './useUpdate';\nexport { default as useUpdateEffect } from './useUpdateEffect';\nexport { default as useUpsert } from './useUpsert';\nexport { default as useVibrate } from './useVibrate';\nexport { default as useVideo } from './useVideo';\nexport { default as useStateValidator } from './useStateValidator';\nexport { useScrollbarWidth } from './useScrollbarWidth';\nexport { useMultiStateValidator } from './useMultiStateValidator';\nexport { default as useWindowScroll } from './useWindowScroll';\nexport { default as useWindowSize } from './useWindowSize';\nexport { default as useMeasure } from './useMeasure';\nexport { default as usePinchZoom } from './usePinchZoom';\nexport { useRendersCount } from './useRendersCount';\nexport { useFirstMountState } from './useFirstMountState';\nexport { default as useSet } from './useSet';\nexport { createGlobalState } from './factory/createGlobalState';\nexport { useHash } from './useHash';\n"
  },
  {
    "path": "src/misc/hookState.ts",
    "content": "export type IHookStateInitialSetter<S> = () => S;\nexport type IHookStateInitAction<S> = S | IHookStateInitialSetter<S>;\n\nexport type IHookStateSetter<S> = ((prevState: S) => S) | (() => S);\nexport type IHookStateSetAction<S> = S | IHookStateSetter<S>;\n\nexport type IHookStateResolvable<S> = S | IHookStateInitialSetter<S> | IHookStateSetter<S>;\n\nexport function resolveHookState<S>(nextState: IHookStateInitAction<S>): S;\nexport function resolveHookState<S, C extends S>(\n  nextState: IHookStateSetAction<S>,\n  currentState?: C\n): S;\nexport function resolveHookState<S, C extends S>(\n  nextState: IHookStateResolvable<S>,\n  currentState?: C\n): S;\nexport function resolveHookState<S, C extends S>(\n  nextState: IHookStateResolvable<S>,\n  currentState?: C\n): S {\n  if (typeof nextState === 'function') {\n    return nextState.length ? (nextState as Function)(currentState) : (nextState as Function)();\n  }\n\n  return nextState;\n}\n"
  },
  {
    "path": "src/misc/isDeepEqual.ts",
    "content": "import isDeepEqualReact from 'fast-deep-equal/react';\n\nexport default isDeepEqualReact;\n"
  },
  {
    "path": "src/misc/parseTimeRanges.ts",
    "content": "export default function parseTimeRanges(ranges) {\n  const result: { start: number; end: number }[] = [];\n\n  for (let i = 0; i < ranges.length; i++) {\n    result.push({\n      start: ranges.start(i),\n      end: ranges.end(i),\n    });\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "src/misc/types.ts",
    "content": "export type PromiseType<P extends Promise<any>> = P extends Promise<infer T> ? T : never;\n\nexport type FunctionReturningPromise = (...args: any[]) => Promise<any>;\n"
  },
  {
    "path": "src/misc/util.ts",
    "content": "export const noop = () => {};\n\nexport function on<T extends Window | Document | HTMLElement | EventTarget>(\n  obj: T | null,\n  ...args: Parameters<T['addEventListener']> | [string, Function | null, ...any]\n): void {\n  if (obj && obj.addEventListener) {\n    obj.addEventListener(...(args as Parameters<HTMLElement['addEventListener']>));\n  }\n}\n\nexport function off<T extends Window | Document | HTMLElement | EventTarget>(\n  obj: T | null,\n  ...args: Parameters<T['removeEventListener']> | [string, Function | null, ...any]\n): void {\n  if (obj && obj.removeEventListener) {\n    obj.removeEventListener(...(args as Parameters<HTMLElement['removeEventListener']>));\n  }\n}\n\nexport const isBrowser = typeof window !== 'undefined';\n\nexport const isNavigator = typeof navigator !== 'undefined';\n"
  },
  {
    "path": "src/useAsync.ts",
    "content": "import { DependencyList, useEffect } from 'react';\nimport useAsyncFn from './useAsyncFn';\nimport { FunctionReturningPromise } from './misc/types';\n\nexport { AsyncState, AsyncFnReturn } from './useAsyncFn';\n\nexport default function useAsync<T extends FunctionReturningPromise>(\n  fn: T,\n  deps: DependencyList = []\n) {\n  const [state, callback] = useAsyncFn(fn, deps, {\n    loading: true,\n  });\n\n  useEffect(() => {\n    callback();\n  }, [callback]);\n\n  return state;\n}\n"
  },
  {
    "path": "src/useAsyncFn.ts",
    "content": "import { DependencyList, useCallback, useRef, useState } from 'react';\nimport useMountedState from './useMountedState';\nimport { FunctionReturningPromise, PromiseType } from './misc/types';\n\nexport type AsyncState<T> =\n  | {\n      loading: boolean;\n      error?: undefined;\n      value?: undefined;\n    }\n  | {\n      loading: true;\n      error?: Error | undefined;\n      value?: T;\n    }\n  | {\n      loading: false;\n      error: Error;\n      value?: undefined;\n    }\n  | {\n      loading: false;\n      error?: undefined;\n      value: T;\n    };\n\ntype StateFromFunctionReturningPromise<T extends FunctionReturningPromise> = AsyncState<\n  PromiseType<ReturnType<T>>\n>;\n\nexport type AsyncFnReturn<T extends FunctionReturningPromise = FunctionReturningPromise> = [\n  StateFromFunctionReturningPromise<T>,\n  T\n];\n\nexport default function useAsyncFn<T extends FunctionReturningPromise>(\n  fn: T,\n  deps: DependencyList = [],\n  initialState: StateFromFunctionReturningPromise<T> = { loading: false }\n): AsyncFnReturn<T> {\n  const lastCallId = useRef(0);\n  const isMounted = useMountedState();\n  const [state, set] = useState<StateFromFunctionReturningPromise<T>>(initialState);\n\n  const callback = useCallback((...args: Parameters<T>): ReturnType<T> => {\n    const callId = ++lastCallId.current;\n\n    if (!state.loading) {\n      set((prevState) => ({ ...prevState, loading: true }));\n    }\n\n    return fn(...args).then(\n      (value) => {\n        isMounted() && callId === lastCallId.current && set({ value, loading: false });\n\n        return value;\n      },\n      (error) => {\n        isMounted() && callId === lastCallId.current && set({ error, loading: false });\n\n        return error;\n      }\n    ) as ReturnType<T>;\n  }, deps);\n\n  return [state, callback as unknown as T];\n}\n"
  },
  {
    "path": "src/useAsyncRetry.ts",
    "content": "import { DependencyList, useCallback, useState } from 'react';\nimport useAsync, { AsyncState } from './useAsync';\n\nexport type AsyncStateRetry<T> = AsyncState<T> & {\n  retry(): void;\n};\n\nconst useAsyncRetry = <T>(fn: () => Promise<T>, deps: DependencyList = []) => {\n  const [attempt, setAttempt] = useState<number>(0);\n  const state = useAsync(fn, [...deps, attempt]);\n\n  const stateLoading = state.loading;\n  const retry = useCallback(() => {\n    if (stateLoading) {\n      if (process.env.NODE_ENV === 'development') {\n        console.log(\n          'You are calling useAsyncRetry hook retry() method while loading in progress, this is a no-op.'\n        );\n      }\n\n      return;\n    }\n\n    setAttempt((currentAttempt) => currentAttempt + 1);\n  }, [...deps, stateLoading]);\n\n  return { ...state, retry };\n};\n\nexport default useAsyncRetry;\n"
  },
  {
    "path": "src/useAudio.ts",
    "content": "import createHTMLMediaHook from './factory/createHTMLMediaHook';\n\nconst useAudio = createHTMLMediaHook<HTMLAudioElement>('audio');\nexport default useAudio;\n"
  },
  {
    "path": "src/useBattery.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { isNavigator, off, on } from './misc/util';\nimport isDeepEqual from './misc/isDeepEqual';\n\nexport interface BatteryState {\n  charging: boolean;\n  chargingTime: number;\n  dischargingTime: number;\n  level: number;\n}\n\ninterface BatteryManager extends Readonly<BatteryState>, EventTarget {\n  onchargingchange: () => void;\n  onchargingtimechange: () => void;\n  ondischargingtimechange: () => void;\n  onlevelchange: () => void;\n}\n\ninterface NavigatorWithPossibleBattery extends Navigator {\n  getBattery?: () => Promise<BatteryManager>;\n}\n\ntype UseBatteryState =\n  | { isSupported: false } // Battery API is not supported\n  | { isSupported: true; fetched: false } // battery API supported but not fetched yet\n  | (BatteryState & { isSupported: true; fetched: true }); // battery API supported and fetched\n\nconst nav: NavigatorWithPossibleBattery | undefined = isNavigator ? navigator : undefined;\nconst isBatteryApiSupported = nav && typeof nav.getBattery === 'function';\n\nfunction useBatteryMock(): UseBatteryState {\n  return { isSupported: false };\n}\n\nfunction useBattery(): UseBatteryState {\n  const [state, setState] = useState<UseBatteryState>({ isSupported: true, fetched: false });\n\n  useEffect(() => {\n    let isMounted = true;\n    let battery: BatteryManager | null = null;\n\n    const handleChange = () => {\n      if (!isMounted || !battery) {\n        return;\n      }\n      const newState: UseBatteryState = {\n        isSupported: true,\n        fetched: true,\n        level: battery.level,\n        charging: battery.charging,\n        dischargingTime: battery.dischargingTime,\n        chargingTime: battery.chargingTime,\n      };\n      !isDeepEqual(state, newState) && setState(newState);\n    };\n\n    nav!.getBattery!().then((bat: BatteryManager) => {\n      if (!isMounted) {\n        return;\n      }\n      battery = bat;\n      on(battery, 'chargingchange', handleChange);\n      on(battery, 'chargingtimechange', handleChange);\n      on(battery, 'dischargingtimechange', handleChange);\n      on(battery, 'levelchange', handleChange);\n      handleChange();\n    });\n\n    return () => {\n      isMounted = false;\n      if (battery) {\n        off(battery, 'chargingchange', handleChange);\n        off(battery, 'chargingtimechange', handleChange);\n        off(battery, 'dischargingtimechange', handleChange);\n        off(battery, 'levelchange', handleChange);\n      }\n    };\n  }, []);\n\n  return state;\n}\n\nexport default isBatteryApiSupported ? useBattery : useBatteryMock;\n"
  },
  {
    "path": "src/useBeforeUnload.ts",
    "content": "import { useCallback, useEffect } from 'react';\nimport { off, on } from './misc/util';\n\nconst useBeforeUnload = (enabled: boolean | (() => boolean) = true, message?: string) => {\n  const handler = useCallback(\n    (event: BeforeUnloadEvent) => {\n      const finalEnabled = typeof enabled === 'function' ? enabled() : true;\n\n      if (!finalEnabled) {\n        return;\n      }\n\n      event.preventDefault();\n\n      if (message) {\n        event.returnValue = message;\n      }\n\n      return message;\n    },\n    [enabled, message]\n  );\n\n  useEffect(() => {\n    if (!enabled) {\n      return;\n    }\n\n    on(window, 'beforeunload', handler);\n\n    return () => off(window, 'beforeunload', handler);\n  }, [enabled, handler]);\n};\n\nexport default useBeforeUnload;\n"
  },
  {
    "path": "src/useBoolean.ts",
    "content": "import useBoolean from './useToggle';\n\nexport default useBoolean;\n"
  },
  {
    "path": "src/useClickAway.ts",
    "content": "import { RefObject, useEffect, useRef } from 'react';\nimport { off, on } from './misc/util';\n\nconst defaultEvents = ['mousedown', 'touchstart'];\n\nconst useClickAway = <E extends Event = Event>(\n  ref: RefObject<HTMLElement | null>,\n  onClickAway: (event: E) => void,\n  events: string[] = defaultEvents\n) => {\n  const savedCallback = useRef(onClickAway);\n  useEffect(() => {\n    savedCallback.current = onClickAway;\n  }, [onClickAway]);\n  useEffect(() => {\n    const handler = (event) => {\n      const { current: el } = ref;\n      el && !el.contains(event.target) && savedCallback.current(event);\n    };\n    for (const eventName of events) {\n      on(document, eventName, handler);\n    }\n    return () => {\n      for (const eventName of events) {\n        off(document, eventName, handler);\n      }\n    };\n  }, [events, ref]);\n};\n\nexport default useClickAway;\n"
  },
  {
    "path": "src/useCookie.ts",
    "content": "import { useCallback, useState } from 'react';\nimport Cookies from 'js-cookie';\n\nconst useCookie = (\n  cookieName: string\n): [string | null, (newValue: string, options?: Cookies.CookieAttributes) => void, () => void] => {\n  const [value, setValue] = useState<string | null>(() => Cookies.get(cookieName) || null);\n\n  const updateCookie = useCallback(\n    (newValue: string, options?: Cookies.CookieAttributes) => {\n      Cookies.set(cookieName, newValue, options);\n      setValue(newValue);\n    },\n    [cookieName]\n  );\n\n  const deleteCookie = useCallback(() => {\n    Cookies.remove(cookieName);\n    setValue(null);\n  }, [cookieName]);\n\n  return [value, updateCookie, deleteCookie];\n};\n\nexport default useCookie;\n"
  },
  {
    "path": "src/useCopyToClipboard.ts",
    "content": "import writeText from 'copy-to-clipboard';\nimport { useCallback } from 'react';\nimport useMountedState from './useMountedState';\nimport useSetState from './useSetState';\n\nexport interface CopyToClipboardState {\n  value?: string;\n  noUserInteraction: boolean;\n  error?: Error;\n}\n\nconst useCopyToClipboard = (): [CopyToClipboardState, (value: string) => void] => {\n  const isMounted = useMountedState();\n  const [state, setState] = useSetState<CopyToClipboardState>({\n    value: undefined,\n    error: undefined,\n    noUserInteraction: true,\n  });\n\n  const copyToClipboard = useCallback((value) => {\n    if (!isMounted()) {\n      return;\n    }\n    let noUserInteraction;\n    let normalizedValue;\n    try {\n      // only strings and numbers casted to strings can be copied to clipboard\n      if (typeof value !== 'string' && typeof value !== 'number') {\n        const error = new Error(\n          `Cannot copy typeof ${typeof value} to clipboard, must be a string`\n        );\n        if (process.env.NODE_ENV === 'development') console.error(error);\n        setState({\n          value,\n          error,\n          noUserInteraction: true,\n        });\n        return;\n      }\n      // empty strings are also considered invalid\n      else if (value === '') {\n        const error = new Error(`Cannot copy empty string to clipboard.`);\n        if (process.env.NODE_ENV === 'development') console.error(error);\n        setState({\n          value,\n          error,\n          noUserInteraction: true,\n        });\n        return;\n      }\n      normalizedValue = value.toString();\n      noUserInteraction = writeText(normalizedValue);\n      setState({\n        value: normalizedValue,\n        error: undefined,\n        noUserInteraction,\n      });\n    } catch (error) {\n      setState({\n        value: normalizedValue,\n        error,\n        noUserInteraction,\n      });\n    }\n  }, []);\n\n  return [state, copyToClipboard];\n};\n\nexport default useCopyToClipboard;\n"
  },
  {
    "path": "src/useCounter.ts",
    "content": "import { useMemo } from 'react';\nimport useGetSet from './useGetSet';\nimport { IHookStateInitAction, IHookStateSetAction, resolveHookState } from './misc/hookState';\n\nexport interface CounterActions {\n  inc: (delta?: number) => void;\n  dec: (delta?: number) => void;\n  get: () => number;\n  set: (value: IHookStateSetAction<number>) => void;\n  reset: (value?: IHookStateSetAction<number>) => void;\n}\n\nexport default function useCounter(\n  initialValue: IHookStateInitAction<number> = 0,\n  max: number | null = null,\n  min: number | null = null\n): [number, CounterActions] {\n  let init = resolveHookState(initialValue);\n\n  typeof init !== 'number' &&\n    console.error('initialValue has to be a number, got ' + typeof initialValue);\n\n  if (typeof min === 'number') {\n    init = Math.max(init, min);\n  } else if (min !== null) {\n    console.error('min has to be a number, got ' + typeof min);\n  }\n\n  if (typeof max === 'number') {\n    init = Math.min(init, max);\n  } else if (max !== null) {\n    console.error('max has to be a number, got ' + typeof max);\n  }\n\n  const [get, setInternal] = useGetSet(init);\n\n  return [\n    get(),\n    useMemo(() => {\n      const set = (newState: IHookStateSetAction<number>) => {\n        const prevState = get();\n        let rState = resolveHookState(newState, prevState);\n\n        if (prevState !== rState) {\n          if (typeof min === 'number') {\n            rState = Math.max(rState, min);\n          }\n          if (typeof max === 'number') {\n            rState = Math.min(rState, max);\n          }\n\n          prevState !== rState && setInternal(rState);\n        }\n      };\n\n      return {\n        get,\n        set,\n        inc: (delta: IHookStateSetAction<number> = 1) => {\n          const rDelta = resolveHookState(delta, get());\n\n          if (typeof rDelta !== 'number') {\n            console.error(\n              'delta has to be a number or function returning a number, got ' + typeof rDelta\n            );\n          }\n\n          set((num: number) => num + rDelta);\n        },\n        dec: (delta: IHookStateSetAction<number> = 1) => {\n          const rDelta = resolveHookState(delta, get());\n\n          if (typeof rDelta !== 'number') {\n            console.error(\n              'delta has to be a number or function returning a number, got ' + typeof rDelta\n            );\n          }\n\n          set((num: number) => num - rDelta);\n        },\n        reset: (value: IHookStateSetAction<number> = init) => {\n          const rValue = resolveHookState(value, get());\n\n          if (typeof rValue !== 'number') {\n            console.error(\n              'value has to be a number or function returning a number, got ' + typeof rValue\n            );\n          }\n\n          // eslint-disable-next-line react-hooks/exhaustive-deps\n          init = rValue;\n          set(rValue);\n        },\n      };\n    }, [init, min, max]),\n  ];\n}\n"
  },
  {
    "path": "src/useCss.ts",
    "content": "import { create, NanoRenderer } from 'nano-css';\nimport { addon as addonCSSOM, CSSOMAddon } from 'nano-css/addon/cssom';\nimport { addon as addonVCSSOM, VCSSOMAddon } from 'nano-css/addon/vcssom';\nimport { cssToTree } from 'nano-css/addon/vcssom/cssToTree';\nimport { useMemo } from 'react';\nimport useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect';\n\ntype Nano = NanoRenderer & CSSOMAddon & VCSSOMAddon;\nconst nano = create() as Nano;\naddonCSSOM(nano);\naddonVCSSOM(nano);\n\nlet counter = 0;\n\nconst useCss = (css: object): string => {\n  const className = useMemo(() => 'react-use-css-' + (counter++).toString(36), []);\n  const sheet = useMemo(() => new nano.VSheet(), []);\n\n  useIsomorphicLayoutEffect(() => {\n    const tree = {};\n    cssToTree(tree, css, '.' + className, '');\n    sheet.diff(tree);\n\n    return () => {\n      sheet.diff({});\n    };\n  });\n\n  return className;\n};\n\nexport default useCss;\n"
  },
  {
    "path": "src/useCustomCompareEffect.ts",
    "content": "import { DependencyList, EffectCallback, useEffect, useRef } from 'react';\n\nconst isPrimitive = (val: any) => val !== Object(val);\n\ntype DepsEqualFnType<TDeps extends DependencyList> = (prevDeps: TDeps, nextDeps: TDeps) => boolean;\n\nconst useCustomCompareEffect = <TDeps extends DependencyList>(\n  effect: EffectCallback,\n  deps: TDeps,\n  depsEqual: DepsEqualFnType<TDeps>\n) => {\n  if (process.env.NODE_ENV !== 'production') {\n    if (!(deps instanceof Array) || !deps.length) {\n      console.warn(\n        '`useCustomCompareEffect` should not be used with no dependencies. Use React.useEffect instead.'\n      );\n    }\n\n    if (deps.every(isPrimitive)) {\n      console.warn(\n        '`useCustomCompareEffect` should not be used with dependencies that are all primitive values. Use React.useEffect instead.'\n      );\n    }\n\n    if (typeof depsEqual !== 'function') {\n      console.warn(\n        '`useCustomCompareEffect` should be used with depsEqual callback for comparing deps list'\n      );\n    }\n  }\n\n  const ref = useRef<TDeps | undefined>(undefined);\n\n  if (!ref.current || !depsEqual(deps, ref.current)) {\n    ref.current = deps;\n  }\n\n  useEffect(effect, ref.current);\n};\n\nexport default useCustomCompareEffect;\n"
  },
  {
    "path": "src/useDebounce.ts",
    "content": "import { DependencyList, useEffect } from 'react';\nimport useTimeoutFn from './useTimeoutFn';\n\nexport type UseDebounceReturn = [() => boolean | null, () => void];\n\nexport default function useDebounce(\n  fn: Function,\n  ms: number = 0,\n  deps: DependencyList = []\n): UseDebounceReturn {\n  const [isReady, cancel, reset] = useTimeoutFn(fn, ms);\n\n  useEffect(reset, deps);\n\n  return [isReady, cancel];\n}\n"
  },
  {
    "path": "src/useDeepCompareEffect.ts",
    "content": "import { DependencyList, EffectCallback } from 'react';\nimport useCustomCompareEffect from './useCustomCompareEffect';\nimport isDeepEqual from './misc/isDeepEqual';\n\nconst isPrimitive = (val: any) => val !== Object(val);\n\nconst useDeepCompareEffect = (effect: EffectCallback, deps: DependencyList) => {\n  if (process.env.NODE_ENV !== 'production') {\n    if (!(deps instanceof Array) || !deps.length) {\n      console.warn(\n        '`useDeepCompareEffect` should not be used with no dependencies. Use React.useEffect instead.'\n      );\n    }\n\n    if (deps.every(isPrimitive)) {\n      console.warn(\n        '`useDeepCompareEffect` should not be used with dependencies that are all primitive values. Use React.useEffect instead.'\n      );\n    }\n  }\n\n  useCustomCompareEffect(effect, deps, isDeepEqual);\n};\n\nexport default useDeepCompareEffect;\n"
  },
  {
    "path": "src/useDefault.ts",
    "content": "import { useState } from 'react';\n\nconst useDefault = <TStateType>(\n  defaultValue: TStateType,\n  initialValue: TStateType | (() => TStateType)\n) => {\n  const [value, setValue] = useState<TStateType | undefined | null>(initialValue);\n\n  if (value === undefined || value === null) {\n    return [defaultValue, setValue] as const;\n  }\n\n  return [value, setValue] as const;\n};\n\nexport default useDefault;\n"
  },
  {
    "path": "src/useDrop.ts",
    "content": "import { useCallback, useEffect, useMemo, useState } from 'react';\nimport { noop, off, on } from './misc/util';\n\nexport interface DropAreaState {\n  over: boolean;\n}\n\nexport interface DropAreaBond {\n  onDragOver: React.DragEventHandler;\n  onDragEnter: React.DragEventHandler;\n  onDragLeave: React.DragEventHandler;\n  onDrop: React.DragEventHandler;\n  onPaste: React.ClipboardEventHandler;\n}\n\nexport interface DropAreaOptions {\n  onFiles?: (files: File[], event?) => void;\n  onText?: (text: string, event?) => void;\n  onUri?: (url: string, event?) => void;\n}\n\nconst createProcess = (options: DropAreaOptions) => (dataTransfer: DataTransfer, event) => {\n  const uri = dataTransfer.getData('text/uri-list');\n\n  if (uri) {\n    (options.onUri || noop)(uri, event);\n    return;\n  }\n\n  if (dataTransfer.files && dataTransfer.files.length) {\n    (options.onFiles || noop)(Array.from(dataTransfer.files), event);\n    return;\n  }\n\n  if (event.clipboardData) {\n    const text = event.clipboardData.getData('text');\n    (options.onText || noop)(text, event);\n    return;\n  }\n};\n\nconst useDrop = (options: DropAreaOptions = {}, args = []): DropAreaState => {\n  const { onFiles, onText, onUri } = options;\n  const [over, setOverRaw] = useState<boolean>(false);\n  const setOver = useCallback(setOverRaw, []);\n  const process = useMemo(() => createProcess(options), [onFiles, onText, onUri]);\n\n  useEffect(() => {\n    const onDragOver = (event) => {\n      event.preventDefault();\n      setOver(true);\n    };\n\n    const onDragEnter = (event) => {\n      event.preventDefault();\n      setOver(true);\n    };\n\n    const onDragLeave = () => {\n      setOver(false);\n    };\n\n    const onDragExit = () => {\n      setOver(false);\n    };\n\n    const onDrop = (event) => {\n      event.preventDefault();\n      setOver(false);\n      process(event.dataTransfer, event);\n    };\n\n    const onPaste = (event) => {\n      process(event.clipboardData, event);\n    };\n\n    on(document, 'dragover', onDragOver);\n    on(document, 'dragenter', onDragEnter);\n    on(document, 'dragleave', onDragLeave);\n    on(document, 'dragexit', onDragExit);\n    on(document, 'drop', onDrop);\n    if (onText) {\n      on(document, 'paste', onPaste);\n    }\n\n    return () => {\n      off(document, 'dragover', onDragOver);\n      off(document, 'dragenter', onDragEnter);\n      off(document, 'dragleave', onDragLeave);\n      off(document, 'dragexit', onDragExit);\n      off(document, 'drop', onDrop);\n      off(document, 'paste', onPaste);\n    };\n  }, [process, ...args]);\n\n  return { over };\n};\n\nexport default useDrop;\n"
  },
  {
    "path": "src/useDropArea.ts",
    "content": "import { useMemo, useState } from 'react';\nimport useMountedState from './useMountedState';\nimport { noop } from './misc/util';\n\nexport interface DropAreaState {\n  over: boolean;\n}\n\nexport interface DropAreaBond {\n  onDragOver: React.DragEventHandler;\n  onDragEnter: React.DragEventHandler;\n  onDragLeave: React.DragEventHandler;\n  onDrop: React.DragEventHandler;\n  onPaste: React.ClipboardEventHandler;\n}\n\nexport interface DropAreaOptions {\n  onFiles?: (files: File[], event?) => void;\n  onText?: (text: string, event?) => void;\n  onUri?: (url: string, event?) => void;\n}\n\n/*\nconst defaultState: DropAreaState = {\n  over: false,\n};\n*/\n\nconst createProcess =\n  (options: DropAreaOptions, mounted: boolean) => (dataTransfer: DataTransfer, event) => {\n    const uri = dataTransfer.getData('text/uri-list');\n\n    if (uri) {\n      (options.onUri || noop)(uri, event);\n      return;\n    }\n\n    if (dataTransfer.files && dataTransfer.files.length) {\n      (options.onFiles || noop)(Array.from(dataTransfer.files), event);\n      return;\n    }\n\n    if (dataTransfer.items && dataTransfer.items.length) {\n      dataTransfer.items[0].getAsString((text) => {\n        if (mounted) {\n          (options.onText || noop)(text, event);\n        }\n      });\n    }\n  };\n\nconst createBond = (process, setOver): DropAreaBond => ({\n  onDragOver: (event) => {\n    event.preventDefault();\n  },\n  onDragEnter: (event) => {\n    event.preventDefault();\n    setOver(true);\n  },\n  onDragLeave: () => {\n    setOver(false);\n  },\n  onDrop: (event) => {\n    event.preventDefault();\n    event.persist();\n    setOver(false);\n    process(event.dataTransfer, event);\n  },\n  onPaste: (event) => {\n    event.persist();\n    process(event.clipboardData, event);\n  },\n});\n\nconst useDropArea = (options: DropAreaOptions = {}): [DropAreaBond, DropAreaState] => {\n  const { onFiles, onText, onUri } = options;\n  const isMounted = useMountedState();\n  const [over, setOver] = useState<boolean>(false);\n  const process = useMemo(() => createProcess(options, isMounted()), [onFiles, onText, onUri]);\n  const bond: DropAreaBond = useMemo(() => createBond(process, setOver), [process, setOver]);\n\n  return [bond, { over }];\n};\n\nexport default useDropArea;\n"
  },
  {
    "path": "src/useEffectOnce.ts",
    "content": "import { EffectCallback, useEffect } from 'react';\n\nconst useEffectOnce = (effect: EffectCallback) => {\n  useEffect(effect, []);\n};\n\nexport default useEffectOnce;\n"
  },
  {
    "path": "src/useEnsuredForwardedRef.ts",
    "content": "import {\n  forwardRef,\n  ForwardRefExoticComponent,\n  MutableRefObject,\n  PropsWithChildren,\n  PropsWithoutRef,\n  RefAttributes,\n  RefForwardingComponent,\n  useEffect,\n  useRef,\n} from 'react';\n\nexport default function useEnsuredForwardedRef<T>(\n  forwardedRef: MutableRefObject<T>\n): MutableRefObject<T> {\n  const ensuredRef = useRef(forwardedRef && forwardedRef.current);\n\n  useEffect(() => {\n    if (!forwardedRef) {\n      return;\n    }\n    forwardedRef.current = ensuredRef.current;\n  }, [forwardedRef]);\n\n  return ensuredRef;\n}\n\nexport function ensuredForwardRef<T, P = {}>(\n  Component: RefForwardingComponent<T, P>\n): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>> {\n  return forwardRef((props: PropsWithChildren<P>, ref) => {\n    const ensuredRef = useEnsuredForwardedRef(ref as MutableRefObject<T>);\n    return Component(props, ensuredRef);\n  });\n}\n"
  },
  {
    "path": "src/useError.ts",
    "content": "import { useCallback, useEffect, useState } from 'react';\n\nconst useError = (): ((err: Error) => void) => {\n  const [error, setError] = useState<Error | null>(null);\n\n  useEffect(() => {\n    if (error) {\n      throw error;\n    }\n  }, [error]);\n\n  const dispatchError = useCallback((err: Error) => {\n    setError(err);\n  }, []);\n\n  return dispatchError;\n};\n\nexport default useError;\n"
  },
  {
    "path": "src/useEvent.ts",
    "content": "import { useEffect } from 'react';\nimport { isBrowser, off, on } from './misc/util';\n\nexport interface ListenerType1 {\n  addEventListener(name: string, handler: (event?: any) => void, ...args: any[]);\n\n  removeEventListener(name: string, handler: (event?: any) => void, ...args: any[]);\n}\n\nexport interface ListenerType2 {\n  on(name: string, handler: (event?: any) => void, ...args: any[]);\n\n  off(name: string, handler: (event?: any) => void, ...args: any[]);\n}\n\nexport type UseEventTarget = ListenerType1 | ListenerType2;\n\nconst defaultTarget = isBrowser ? window : null;\n\nconst isListenerType1 = (target: any): target is ListenerType1 => {\n  return !!target.addEventListener;\n};\nconst isListenerType2 = (target: any): target is ListenerType2 => {\n  return !!target.on;\n};\n\ntype AddEventListener<T> = T extends ListenerType1\n  ? T['addEventListener']\n  : T extends ListenerType2\n  ? T['on']\n  : never;\n\nexport type UseEventOptions<T> = Parameters<AddEventListener<T>>[2];\n\nconst useEvent = <T extends UseEventTarget>(\n  name: Parameters<AddEventListener<T>>[0],\n  handler?: null | undefined | Parameters<AddEventListener<T>>[1],\n  target: null | T | Window = defaultTarget,\n  options?: UseEventOptions<T>\n) => {\n  useEffect(() => {\n    if (!handler) {\n      return;\n    }\n    if (!target) {\n      return;\n    }\n    if (isListenerType1(target)) {\n      on(target, name, handler, options);\n    } else if (isListenerType2(target)) {\n      target.on(name, handler, options);\n    }\n    return () => {\n      if (isListenerType1(target)) {\n        off(target, name, handler, options);\n      } else if (isListenerType2(target)) {\n        target.off(name, handler, options);\n      }\n    };\n  }, [name, handler, target, JSON.stringify(options)]);\n};\n\nexport default useEvent;\n"
  },
  {
    "path": "src/useFavicon.ts",
    "content": "import { useEffect } from 'react';\n\nconst useFavicon = (href: string) => {\n  useEffect(() => {\n    const link: HTMLLinkElement =\n      document.querySelector(\"link[rel*='icon']\") || document.createElement('link');\n    link.type = 'image/x-icon';\n    link.rel = 'shortcut icon';\n    link.href = href;\n    document.getElementsByTagName('head')[0].appendChild(link);\n  }, [href]);\n};\n\nexport default useFavicon;\n"
  },
  {
    "path": "src/useFirstMountState.ts",
    "content": "import { useRef } from 'react';\n\nexport function useFirstMountState(): boolean {\n  const isFirst = useRef(true);\n\n  if (isFirst.current) {\n    isFirst.current = false;\n\n    return true;\n  }\n\n  return isFirst.current;\n}\n"
  },
  {
    "path": "src/useFullscreen.ts",
    "content": "import { RefObject, useState } from 'react';\nimport screenfull from 'screenfull';\nimport useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect';\nimport { noop, off, on } from './misc/util';\n\nexport interface FullScreenOptions {\n  video?: RefObject<\n    HTMLVideoElement & { webkitEnterFullscreen?: () => void; webkitExitFullscreen?: () => void }\n  >;\n  onClose?: (error?: Error) => void;\n}\n\nconst useFullscreen = (\n  ref: RefObject<Element>,\n  enabled: boolean,\n  options: FullScreenOptions = {}\n): boolean => {\n  const { video, onClose = noop } = options;\n  const [isFullscreen, setIsFullscreen] = useState(enabled);\n\n  useIsomorphicLayoutEffect(() => {\n    if (!enabled) {\n      return;\n    }\n    if (!ref.current) {\n      return;\n    }\n\n    const onWebkitEndFullscreen = () => {\n      if (video?.current) {\n        off(video.current, 'webkitendfullscreen', onWebkitEndFullscreen);\n      }\n      onClose();\n    };\n\n    const onChange = () => {\n      if (screenfull.isEnabled) {\n        const isScreenfullFullscreen = screenfull.isFullscreen;\n        setIsFullscreen(isScreenfullFullscreen);\n        if (!isScreenfullFullscreen) {\n          onClose();\n        }\n      }\n    };\n\n    if (screenfull.isEnabled) {\n      try {\n        screenfull.request(ref.current);\n        setIsFullscreen(true);\n      } catch (error) {\n        onClose(error);\n        setIsFullscreen(false);\n      }\n      screenfull.on('change', onChange);\n    } else if (video && video.current && video.current.webkitEnterFullscreen) {\n      video.current.webkitEnterFullscreen();\n      on(video.current, 'webkitendfullscreen', onWebkitEndFullscreen);\n      setIsFullscreen(true);\n    } else {\n      onClose();\n      setIsFullscreen(false);\n    }\n\n    return () => {\n      setIsFullscreen(false);\n      if (screenfull.isEnabled) {\n        try {\n          screenfull.off('change', onChange);\n          screenfull.exit();\n        } catch {}\n      } else if (video && video.current && video.current.webkitExitFullscreen) {\n        off(video.current, 'webkitendfullscreen', onWebkitEndFullscreen);\n        video.current.webkitExitFullscreen();\n      }\n    };\n  }, [enabled, video, ref]);\n\n  return isFullscreen;\n};\n\nexport default useFullscreen;\n"
  },
  {
    "path": "src/useGeolocation.ts",
    "content": "import { useEffect, useState } from 'react';\n\n/**\n * @desc Made compatible with {GeolocationPositionError} and {PositionError} cause\n * PositionError been renamed to GeolocationPositionError in typescript 4.1.x and making\n * own compatible interface is most easiest way to avoid errors.\n */\nexport interface IGeolocationPositionError {\n  readonly code: number;\n  readonly message: string;\n  readonly PERMISSION_DENIED: number;\n  readonly POSITION_UNAVAILABLE: number;\n  readonly TIMEOUT: number;\n}\n\nexport interface GeoLocationSensorState {\n  loading: boolean;\n  accuracy: number | null;\n  altitude: number | null;\n  altitudeAccuracy: number | null;\n  heading: number | null;\n  latitude: number | null;\n  longitude: number | null;\n  speed: number | null;\n  timestamp: number | null;\n  error?: Error | IGeolocationPositionError;\n}\n\nconst useGeolocation = (options?: PositionOptions): GeoLocationSensorState => {\n  const [state, setState] = useState<GeoLocationSensorState>({\n    loading: true,\n    accuracy: null,\n    altitude: null,\n    altitudeAccuracy: null,\n    heading: null,\n    latitude: null,\n    longitude: null,\n    speed: null,\n    timestamp: Date.now(),\n  });\n  let mounted = true;\n  let watchId: any;\n\n  const onEvent = (event: any) => {\n    if (mounted) {\n      setState({\n        loading: false,\n        accuracy: event.coords.accuracy,\n        altitude: event.coords.altitude,\n        altitudeAccuracy: event.coords.altitudeAccuracy,\n        heading: event.coords.heading,\n        latitude: event.coords.latitude,\n        longitude: event.coords.longitude,\n        speed: event.coords.speed,\n        timestamp: event.timestamp,\n      });\n    }\n  };\n  const onEventError = (error: IGeolocationPositionError) =>\n    mounted && setState((oldState) => ({ ...oldState, loading: false, error }));\n\n  useEffect(() => {\n    navigator.geolocation.getCurrentPosition(onEvent, onEventError, options);\n    watchId = navigator.geolocation.watchPosition(onEvent, onEventError, options);\n\n    return () => {\n      mounted = false;\n      navigator.geolocation.clearWatch(watchId);\n    };\n  }, []);\n\n  return state;\n};\n\nexport default useGeolocation;\n"
  },
  {
    "path": "src/useGetSet.ts",
    "content": "import { Dispatch, useMemo, useRef } from 'react';\nimport useUpdate from './useUpdate';\nimport { IHookStateInitAction, IHookStateSetAction, resolveHookState } from './misc/hookState';\n\nexport default function useGetSet<S>(\n  initialState: IHookStateInitAction<S>\n): [get: () => S, set: Dispatch<IHookStateSetAction<S>>] {\n  const state = useRef(resolveHookState(initialState));\n  const update = useUpdate();\n\n  return useMemo(\n    () => [\n      () => state.current as S,\n      (newState: IHookStateSetAction<S>) => {\n        state.current = resolveHookState(newState, state.current);\n        update();\n      },\n    ],\n    []\n  );\n}\n"
  },
  {
    "path": "src/useGetSetState.ts",
    "content": "import { useCallback, useRef } from 'react';\nimport useUpdate from './useUpdate';\n\nconst useGetSetState = <T extends object>(\n  initialState: T = {} as T\n): [() => T, (patch: Partial<T>) => void] => {\n  if (process.env.NODE_ENV !== 'production') {\n    if (typeof initialState !== 'object') {\n      console.error('useGetSetState initial state must be an object.');\n    }\n  }\n\n  const update = useUpdate();\n  const state = useRef<T>({ ...(initialState as object) } as T);\n  const get = useCallback(() => state.current, []);\n  const set = useCallback((patch: Partial<T>) => {\n    if (!patch) {\n      return;\n    }\n    if (process.env.NODE_ENV !== 'production') {\n      if (typeof patch !== 'object') {\n        console.error('useGetSetState setter patch must be an object.');\n      }\n    }\n    Object.assign(state.current, patch);\n    update();\n  }, []);\n\n  return [get, set];\n};\n\nexport default useGetSetState;\n"
  },
  {
    "path": "src/useHarmonicIntervalFn.ts",
    "content": "import { useEffect, useRef } from 'react';\nimport { clearHarmonicInterval, setHarmonicInterval } from 'set-harmonic-interval';\n\nconst useHarmonicIntervalFn = (fn: Function, delay: number | null = 0) => {\n  const latestCallback = useRef<Function>(() => {});\n\n  useEffect(() => {\n    latestCallback.current = fn;\n  });\n\n  useEffect(() => {\n    if (delay !== null) {\n      const interval = setHarmonicInterval(() => latestCallback.current(), delay);\n      return () => clearHarmonicInterval(interval);\n    }\n    return undefined;\n  }, [delay]);\n};\n\nexport default useHarmonicIntervalFn;\n"
  },
  {
    "path": "src/useHash.ts",
    "content": "import { useCallback, useState } from 'react';\nimport useLifecycles from './useLifecycles';\nimport { off, on } from './misc/util';\n\n/**\n * read and write url hash, response to url hash change\n */\nexport const useHash = () => {\n  const [hash, setHash] = useState(() => window.location.hash);\n\n  const onHashChange = useCallback(() => {\n    setHash(window.location.hash);\n  }, []);\n\n  useLifecycles(\n    () => {\n      on(window, 'hashchange', onHashChange);\n    },\n    () => {\n      off(window, 'hashchange', onHashChange);\n    }\n  );\n\n  const _setHash = useCallback(\n    (newHash: string) => {\n      if (newHash !== hash) {\n        window.location.hash = newHash;\n      }\n    },\n    [hash]\n  );\n\n  return [hash, _setHash] as const;\n};\n"
  },
  {
    "path": "src/useHover.ts",
    "content": "import * as React from 'react';\nimport { noop } from './misc/util';\n\nconst { useState } = React;\n\nexport type Element = ((state: boolean) => React.ReactElement<any>) | React.ReactElement<any>;\n\nconst useHover = (element: Element): [React.ReactElement<any>, boolean] => {\n  const [state, setState] = useState(false);\n\n  const onMouseEnter = (originalOnMouseEnter?: any) => (event: any) => {\n    (originalOnMouseEnter || noop)(event);\n    setState(true);\n  };\n  const onMouseLeave = (originalOnMouseLeave?: any) => (event: any) => {\n    (originalOnMouseLeave || noop)(event);\n    setState(false);\n  };\n\n  if (typeof element === 'function') {\n    element = element(state);\n  }\n\n  const el = React.cloneElement(element, {\n    onMouseEnter: onMouseEnter(element.props.onMouseEnter),\n    onMouseLeave: onMouseLeave(element.props.onMouseLeave),\n  });\n\n  return [el, state];\n};\n\nexport default useHover;\n"
  },
  {
    "path": "src/useHoverDirty.ts",
    "content": "import { RefObject, useEffect, useState } from 'react';\nimport { off, on } from './misc/util';\n\n// kudos: https://usehooks.com/\nconst useHoverDirty = (ref: RefObject<Element>, enabled: boolean = true) => {\n  if (process.env.NODE_ENV === 'development') {\n    if (typeof ref !== 'object' || typeof ref.current === 'undefined') {\n      console.error('useHoverDirty expects a single ref argument.');\n    }\n  }\n\n  const [value, setValue] = useState(false);\n\n  useEffect(() => {\n    const onMouseOver = () => setValue(true);\n    const onMouseOut = () => setValue(false);\n\n    if (enabled && ref && ref.current) {\n      on(ref.current, 'mouseover', onMouseOver);\n      on(ref.current, 'mouseout', onMouseOut);\n    }\n\n    // fixes react-hooks/exhaustive-deps warning about stale ref elements\n    const { current } = ref;\n\n    return () => {\n      if (enabled && current) {\n        off(current, 'mouseover', onMouseOver);\n        off(current, 'mouseout', onMouseOut);\n      }\n    };\n  }, [enabled, ref]);\n\n  return value;\n};\n\nexport default useHoverDirty;\n"
  },
  {
    "path": "src/useIdle.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { throttle } from 'throttle-debounce';\nimport { off, on } from './misc/util';\n\nconst defaultEvents = ['mousemove', 'mousedown', 'resize', 'keydown', 'touchstart', 'wheel'];\nconst oneMinute = 60e3;\n\nconst useIdle = (\n  ms: number = oneMinute,\n  initialState: boolean = false,\n  events: string[] = defaultEvents\n): boolean => {\n  const [state, setState] = useState<boolean>(initialState);\n\n  useEffect(() => {\n    let mounted = true;\n    let timeout: any;\n    let localState: boolean = state;\n    const set = (newState: boolean) => {\n      if (mounted) {\n        localState = newState;\n        setState(newState);\n      }\n    };\n\n    const onEvent = throttle(50, () => {\n      if (localState) {\n        set(false);\n      }\n\n      clearTimeout(timeout);\n      timeout = setTimeout(() => set(true), ms);\n    });\n    const onVisibility = () => {\n      if (!document.hidden) {\n        onEvent();\n      }\n    };\n\n    for (let i = 0; i < events.length; i++) {\n      on(window, events[i], onEvent);\n    }\n    on(document, 'visibilitychange', onVisibility);\n\n    timeout = setTimeout(() => set(true), ms);\n\n    return () => {\n      mounted = false;\n\n      for (let i = 0; i < events.length; i++) {\n        off(window, events[i], onEvent);\n      }\n      off(document, 'visibilitychange', onVisibility);\n    };\n  }, [ms, events]);\n\n  return state;\n};\n\nexport default useIdle;\n"
  },
  {
    "path": "src/useIntersection.ts",
    "content": "import { RefObject, useEffect, useState } from 'react';\n\nconst useIntersection = (\n  ref: RefObject<HTMLElement>,\n  options: IntersectionObserverInit\n): IntersectionObserverEntry | null => {\n  const [intersectionObserverEntry, setIntersectionObserverEntry] =\n    useState<IntersectionObserverEntry | null>(null);\n\n  useEffect(() => {\n    if (ref.current && typeof IntersectionObserver === 'function') {\n      const handler = (entries: IntersectionObserverEntry[]) => {\n        setIntersectionObserverEntry(entries[0]);\n      };\n\n      const observer = new IntersectionObserver(handler, options);\n      observer.observe(ref.current);\n\n      return () => {\n        setIntersectionObserverEntry(null);\n        observer.disconnect();\n      };\n    }\n    return () => {};\n  }, [ref.current, options.threshold, options.root, options.rootMargin]);\n\n  return intersectionObserverEntry;\n};\n\nexport default useIntersection;\n"
  },
  {
    "path": "src/useInterval.ts",
    "content": "import { useEffect, useRef } from 'react';\n\nconst useInterval = (callback: Function, delay?: number | null) => {\n  const savedCallback = useRef<Function>(() => {});\n\n  useEffect(() => {\n    savedCallback.current = callback;\n  });\n\n  useEffect(() => {\n    if (delay !== null) {\n      const interval = setInterval(() => savedCallback.current(), delay || 0);\n      return () => clearInterval(interval);\n    }\n\n    return undefined;\n  }, [delay]);\n};\n\nexport default useInterval;\n"
  },
  {
    "path": "src/useIsomorphicLayoutEffect.ts",
    "content": "import { useEffect, useLayoutEffect } from 'react';\nimport { isBrowser } from './misc/util';\n\nconst useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;\n\nexport default useIsomorphicLayoutEffect;\n"
  },
  {
    "path": "src/useKey.ts",
    "content": "import { DependencyList, useMemo } from 'react';\nimport useEvent, { UseEventOptions, UseEventTarget } from './useEvent';\nimport { noop } from './misc/util';\n\nexport type KeyPredicate = (event: KeyboardEvent) => boolean;\nexport type KeyFilter = null | undefined | string | ((event: KeyboardEvent) => boolean);\nexport type Handler = (event: KeyboardEvent) => void;\n\nexport interface UseKeyOptions<T extends UseEventTarget> {\n  event?: 'keydown' | 'keypress' | 'keyup';\n  target?: T | null;\n  options?: UseEventOptions<T>;\n}\n\nconst createKeyPredicate = (keyFilter: KeyFilter): KeyPredicate =>\n  typeof keyFilter === 'function'\n    ? keyFilter\n    : typeof keyFilter === 'string'\n    ? (event: KeyboardEvent) => event.key === keyFilter\n    : keyFilter\n    ? () => true\n    : () => false;\n\nconst useKey = <T extends UseEventTarget>(\n  key: KeyFilter,\n  fn: Handler = noop,\n  opts: UseKeyOptions<T> = {},\n  deps: DependencyList = [key]\n) => {\n  const { event = 'keydown', target, options } = opts;\n  const useMemoHandler = useMemo(() => {\n    const predicate: KeyPredicate = createKeyPredicate(key);\n    const handler: Handler = (handlerEvent) => {\n      if (predicate(handlerEvent)) {\n        return fn(handlerEvent);\n      }\n    };\n    return handler;\n  }, deps);\n  useEvent(event, useMemoHandler, target, options);\n};\n\nexport default useKey;\n"
  },
  {
    "path": "src/useKeyPress.ts",
    "content": "import { useState } from 'react';\nimport useKey, { KeyFilter } from './useKey';\n\nconst useKeyPress = (keyFilter: KeyFilter) => {\n  const [state, set] = useState<[boolean, null | KeyboardEvent]>([false, null]);\n  useKey(keyFilter, (event) => set([true, event]), { event: 'keydown' }, [state]);\n  useKey(keyFilter, (event) => set([false, event]), { event: 'keyup' }, [state]);\n  return state;\n};\n\nexport default useKeyPress;\n"
  },
  {
    "path": "src/useKeyPressEvent.ts",
    "content": "import { Handler, KeyFilter } from './useKey';\nimport useKeyPressDefault from './useKeyPress';\nimport useUpdateEffect from './useUpdateEffect';\n\nconst useKeyPressEvent = (\n  key: string | KeyFilter,\n  keydown?: Handler | null | undefined,\n  keyup?: Handler | null | undefined,\n  useKeyPress = useKeyPressDefault\n) => {\n  const [pressed, event] = useKeyPress(key);\n  useUpdateEffect(() => {\n    if (!pressed && keyup) {\n      keyup(event!);\n    } else if (pressed && keydown) {\n      keydown(event!);\n    }\n  }, [pressed]);\n};\n\nexport default useKeyPressEvent;\n"
  },
  {
    "path": "src/useKeyboardJs.ts",
    "content": "import { useEffect, useState } from 'react';\nimport useMount from './useMount';\n\nconst useKeyboardJs = (combination: string | string[]) => {\n  const [state, set] = useState<[boolean, null | KeyboardEvent]>([false, null]);\n  const [keyboardJs, setKeyboardJs] = useState<any>(null);\n\n  useMount(() => {\n    import('keyboardjs').then((k) => setKeyboardJs(k.default || k));\n  });\n\n  useEffect(() => {\n    if (!keyboardJs) {\n      return;\n    }\n\n    const down = (event) => set([true, event]);\n    const up = (event) => set([false, event]);\n    keyboardJs.bind(combination, down, up, true);\n\n    return () => {\n      keyboardJs.unbind(combination, down, up);\n    };\n  }, [combination, keyboardJs]);\n\n  return state;\n};\n\nexport default useKeyboardJs;\n"
  },
  {
    "path": "src/useLatest.ts",
    "content": "import { useRef } from 'react';\n\nconst useLatest = <T>(value: T): { readonly current: T } => {\n  const ref = useRef(value);\n  ref.current = value;\n  return ref;\n};\n\nexport default useLatest;\n"
  },
  {
    "path": "src/useLifecycles.ts",
    "content": "import { useEffect } from 'react';\n\nconst useLifecycles = (mount, unmount?) => {\n  useEffect(() => {\n    if (mount) {\n      mount();\n    }\n    return () => {\n      if (unmount) {\n        unmount();\n      }\n    };\n  }, []);\n};\n\nexport default useLifecycles;\n"
  },
  {
    "path": "src/useList.ts",
    "content": "import { useMemo, useRef } from 'react';\nimport useUpdate from './useUpdate';\nimport { IHookStateInitAction, IHookStateSetAction, resolveHookState } from './misc/hookState';\n\nexport interface ListActions<T> {\n  /**\n   * @description Set new list instead old one\n   */\n  set: (newList: IHookStateSetAction<T[]>) => void;\n  /**\n   * @description Add item(s) at the end of list\n   */\n  push: (...items: T[]) => void;\n\n  /**\n   * @description Replace item at given position. If item at given position not exists it will be set.\n   */\n  updateAt: (index: number, item: T) => void;\n  /**\n   * @description Insert item at given position, all items to the right will be shifted.\n   */\n  insertAt: (index: number, item: T) => void;\n\n  /**\n   * @description Replace all items that matches predicate with given one.\n   */\n  update: (predicate: (a: T, b: T) => boolean, newItem: T) => void;\n  /**\n   * @description Replace first item matching predicate with given one.\n   */\n  updateFirst: (predicate: (a: T, b: T) => boolean, newItem: T) => void;\n  /**\n   * @description Like `updateFirst` bit in case of predicate miss - pushes item to the list\n   */\n  upsert: (predicate: (a: T, b: T) => boolean, newItem: T) => void;\n\n  /**\n   * @description Sort list with given sorting function\n   */\n  sort: (compareFn?: (a: T, b: T) => number) => void;\n  /**\n   * @description Same as native Array's method\n   */\n  filter: (callbackFn: (value: T, index?: number, array?: T[]) => boolean, thisArg?: any) => void;\n\n  /**\n   * @description Removes item at given position. All items to the right from removed will be shifted.\n   */\n  removeAt: (index: number) => void;\n  /**\n   * @deprecated Use removeAt method instead\n   */\n  remove: (index: number) => void;\n\n  /**\n   * @description Make the list empty\n   */\n  clear: () => void;\n  /**\n   * @description Reset list to initial value\n   */\n  reset: () => void;\n}\n\nfunction useList<T>(initialList: IHookStateInitAction<T[]> = []): [T[], ListActions<T>] {\n  const list = useRef(resolveHookState(initialList));\n  const update = useUpdate();\n\n  const actions = useMemo<ListActions<T>>(() => {\n    const a = {\n      set: (newList: IHookStateSetAction<T[]>) => {\n        list.current = resolveHookState(newList, list.current);\n        update();\n      },\n\n      push: (...items: T[]) => {\n        items.length && actions.set((curr: T[]) => curr.concat(items));\n      },\n\n      updateAt: (index: number, item: T) => {\n        actions.set((curr: T[]) => {\n          const arr = curr.slice();\n\n          arr[index] = item;\n\n          return arr;\n        });\n      },\n\n      insertAt: (index: number, item: T) => {\n        actions.set((curr: T[]) => {\n          const arr = curr.slice();\n\n          index > arr.length ? (arr[index] = item) : arr.splice(index, 0, item);\n\n          return arr;\n        });\n      },\n\n      update: (predicate: (a: T, b: T) => boolean, newItem: T) => {\n        actions.set((curr: T[]) => curr.map((item) => (predicate(item, newItem) ? newItem : item)));\n      },\n\n      updateFirst: (predicate: (a: T, b: T) => boolean, newItem: T) => {\n        const index = list.current.findIndex((item) => predicate(item, newItem));\n\n        index >= 0 && actions.updateAt(index, newItem);\n      },\n\n      upsert: (predicate: (a: T, b: T) => boolean, newItem: T) => {\n        const index = list.current.findIndex((item) => predicate(item, newItem));\n\n        index >= 0 ? actions.updateAt(index, newItem) : actions.push(newItem);\n      },\n\n      sort: (compareFn?: (a: T, b: T) => number) => {\n        actions.set((curr: T[]) => curr.slice().sort(compareFn));\n      },\n\n      filter: <S extends T>(\n        callbackFn: (value: T, index: number, array: T[]) => value is S,\n        thisArg?: any\n      ) => {\n        actions.set((curr: T[]) => curr.slice().filter(callbackFn, thisArg));\n      },\n\n      removeAt: (index: number) => {\n        actions.set((curr: T[]) => {\n          const arr = curr.slice();\n\n          arr.splice(index, 1);\n\n          return arr;\n        });\n      },\n\n      clear: () => {\n        actions.set([]);\n      },\n\n      reset: () => {\n        actions.set(resolveHookState(initialList).slice());\n      },\n    };\n\n    /**\n     * @deprecated Use removeAt method instead\n     */\n    (a as ListActions<T>).remove = a.removeAt;\n\n    return a as ListActions<T>;\n  }, []);\n\n  return [list.current, actions];\n}\n\nexport default useList;\n"
  },
  {
    "path": "src/useLocalStorage.ts",
    "content": "import { Dispatch, SetStateAction, useCallback, useState, useRef, useLayoutEffect } from 'react';\nimport { isBrowser, noop } from './misc/util';\n\ntype parserOptions<T> =\n  | {\n      raw: true;\n    }\n  | {\n      raw: false;\n      serializer: (value: T) => string;\n      deserializer: (value: string) => T;\n    };\n\nconst useLocalStorage = <T>(\n  key: string,\n  initialValue?: T,\n  options?: parserOptions<T>\n): [T | undefined, Dispatch<SetStateAction<T | undefined>>, () => void] => {\n  if (!isBrowser) {\n    return [initialValue as T, noop, noop];\n  }\n  if (!key) {\n    throw new Error('useLocalStorage key may not be falsy');\n  }\n\n  const deserializer = options\n    ? options.raw\n      ? (value) => value\n      : options.deserializer\n    : JSON.parse;\n\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  const initializer = useRef((key: string) => {\n    try {\n      const serializer = options ? (options.raw ? String : options.serializer) : JSON.stringify;\n\n      const localStorageValue = localStorage.getItem(key);\n      if (localStorageValue !== null) {\n        return deserializer(localStorageValue);\n      } else {\n        initialValue && localStorage.setItem(key, serializer(initialValue));\n        return initialValue;\n      }\n    } catch {\n      // If user is in private mode or has storage restriction\n      // localStorage can throw. JSON.parse and JSON.stringify\n      // can throw, too.\n      return initialValue;\n    }\n  });\n\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  const [state, setState] = useState<T | undefined>(() => initializer.current(key));\n\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  useLayoutEffect(() => setState(initializer.current(key)), [key]);\n\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  const set: Dispatch<SetStateAction<T | undefined>> = useCallback(\n    (valOrFunc) => {\n      try {\n        const newState =\n          typeof valOrFunc === 'function' ? (valOrFunc as Function)(state) : valOrFunc;\n        if (typeof newState === 'undefined') return;\n        let value: string;\n\n        if (options)\n          if (options.raw)\n            if (typeof newState === 'string') value = newState;\n            else value = JSON.stringify(newState);\n          else if (options.serializer) value = options.serializer(newState);\n          else value = JSON.stringify(newState);\n        else value = JSON.stringify(newState);\n\n        localStorage.setItem(key, value);\n        setState(deserializer(value));\n      } catch {\n        // If user is in private mode or has storage restriction\n        // localStorage can throw. Also JSON.stringify can throw.\n      }\n    },\n    [key, setState]\n  );\n\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  const remove = useCallback(() => {\n    try {\n      localStorage.removeItem(key);\n      setState(undefined);\n    } catch {\n      // If user is in private mode or has storage restriction\n      // localStorage can throw.\n    }\n  }, [key, setState]);\n\n  return [state, set, remove];\n};\n\nexport default useLocalStorage;\n"
  },
  {
    "path": "src/useLocation.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { isBrowser, off, on } from './misc/util';\n\nconst patchHistoryMethod = (method) => {\n  const history = window.history;\n  const original = history[method];\n\n  history[method] = function (state) {\n    const result = original.apply(this, arguments);\n    const event = new Event(method.toLowerCase());\n\n    (event as any).state = state;\n\n    window.dispatchEvent(event);\n\n    return result;\n  };\n};\n\nif (isBrowser) {\n  patchHistoryMethod('pushState');\n  patchHistoryMethod('replaceState');\n}\n\nexport interface LocationSensorState {\n  trigger: string;\n  state?: any;\n  length?: number;\n  hash?: string;\n  host?: string;\n  hostname?: string;\n  href?: string;\n  origin?: string;\n  pathname?: string;\n  port?: string;\n  protocol?: string;\n  search?: string;\n}\n\nconst useLocationServer = (): LocationSensorState => ({\n  trigger: 'load',\n  length: 1,\n});\n\nconst buildState = (trigger: string) => {\n  const { state, length } = window.history;\n\n  const { hash, host, hostname, href, origin, pathname, port, protocol, search } = window.location;\n\n  return {\n    trigger,\n    state,\n    length,\n    hash,\n    host,\n    hostname,\n    href,\n    origin,\n    pathname,\n    port,\n    protocol,\n    search,\n  };\n};\n\nconst useLocationBrowser = (): LocationSensorState => {\n  const [state, setState] = useState(buildState('load'));\n\n  useEffect(() => {\n    const onPopstate = () => setState(buildState('popstate'));\n    const onPushstate = () => setState(buildState('pushstate'));\n    const onReplacestate = () => setState(buildState('replacestate'));\n\n    on(window, 'popstate', onPopstate);\n    on(window, 'pushstate', onPushstate);\n    on(window, 'replacestate', onReplacestate);\n\n    return () => {\n      off(window, 'popstate', onPopstate);\n      off(window, 'pushstate', onPushstate);\n      off(window, 'replacestate', onReplacestate);\n    };\n  }, []);\n\n  return state;\n};\n\nconst hasEventConstructor = typeof Event === 'function';\n\nexport default isBrowser && hasEventConstructor ? useLocationBrowser : useLocationServer;\n"
  },
  {
    "path": "src/useLockBodyScroll.ts",
    "content": "import { RefObject, useEffect, useRef } from 'react';\nimport { isBrowser, off, on } from './misc/util';\n\nexport function getClosestBody(\n  el: Element | HTMLElement | HTMLIFrameElement | null\n): HTMLElement | null {\n  if (!el) {\n    return null;\n  } else if (el.tagName === 'BODY') {\n    return el as HTMLElement;\n  } else if (el.tagName === 'IFRAME') {\n    const document = (el as HTMLIFrameElement).contentDocument;\n    return document ? document.body : null;\n  } else if (!(el as HTMLElement).offsetParent) {\n    return null;\n  }\n\n  return getClosestBody((el as HTMLElement).offsetParent!);\n}\n\nfunction preventDefault(rawEvent: TouchEvent): boolean {\n  const e = rawEvent || window.event;\n  // Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom).\n  if (e.touches.length > 1) return true;\n\n  if (e.preventDefault) e.preventDefault();\n\n  return false;\n}\n\nexport interface BodyInfoItem {\n  counter: number;\n  initialOverflow: CSSStyleDeclaration['overflow'];\n}\n\nconst isIosDevice =\n  isBrowser &&\n  window.navigator &&\n  window.navigator.platform &&\n  /iP(ad|hone|od)/.test(window.navigator.platform);\n\nconst bodies: Map<HTMLElement, BodyInfoItem> = new Map();\n\nconst doc: Document | undefined = typeof document === 'object' ? document : undefined;\n\nlet documentListenerAdded = false;\n\nexport default !doc\n  ? function useLockBodyMock(_locked: boolean = true, _elementRef?: RefObject<HTMLElement>) {}\n  : function useLockBody(locked: boolean = true, elementRef?: RefObject<HTMLElement>) {\n      const bodyRef = useRef(doc!.body);\n      elementRef = elementRef || bodyRef;\n\n      const lock = (body) => {\n        const bodyInfo = bodies.get(body);\n        if (!bodyInfo) {\n          bodies.set(body, { counter: 1, initialOverflow: body.style.overflow });\n          if (isIosDevice) {\n            if (!documentListenerAdded) {\n              on(document, 'touchmove', preventDefault, { passive: false });\n\n              documentListenerAdded = true;\n            }\n          } else {\n            body.style.overflow = 'hidden';\n          }\n        } else {\n          bodies.set(body, {\n            counter: bodyInfo.counter + 1,\n            initialOverflow: bodyInfo.initialOverflow,\n          });\n        }\n      };\n\n      const unlock = (body) => {\n        const bodyInfo = bodies.get(body);\n        if (bodyInfo) {\n          if (bodyInfo.counter === 1) {\n            bodies.delete(body);\n            if (isIosDevice) {\n              body.ontouchmove = null;\n\n              if (documentListenerAdded) {\n                off(document, 'touchmove', preventDefault);\n                documentListenerAdded = false;\n              }\n            } else {\n              body.style.overflow = bodyInfo.initialOverflow;\n            }\n          } else {\n            bodies.set(body, {\n              counter: bodyInfo.counter - 1,\n              initialOverflow: bodyInfo.initialOverflow,\n            });\n          }\n        }\n      };\n\n      useEffect(() => {\n        const body = getClosestBody(elementRef!.current);\n        if (!body) {\n          return;\n        }\n        if (locked) {\n          lock(body);\n        } else {\n          unlock(body);\n        }\n      }, [locked, elementRef.current]);\n\n      // clean up, on un-mount\n      useEffect(() => {\n        const body = getClosestBody(elementRef!.current);\n        if (!body) {\n          return;\n        }\n        return () => {\n          unlock(body);\n        };\n      }, []);\n    };\n"
  },
  {
    "path": "src/useLogger.ts",
    "content": "import useEffectOnce from './useEffectOnce';\nimport useUpdateEffect from './useUpdateEffect';\n\nconst useLogger = (componentName: string, ...rest) => {\n  useEffectOnce(() => {\n    console.log(`${componentName} mounted`, ...rest);\n    return () => console.log(`${componentName} unmounted`);\n  });\n\n  useUpdateEffect(() => {\n    console.log(`${componentName} updated`, ...rest);\n  });\n};\n\nexport default useLogger;\n"
  },
  {
    "path": "src/useLongPress.ts",
    "content": "import { useCallback, useRef } from 'react';\nimport { off, on } from './misc/util';\n\ninterface Options {\n  isPreventDefault?: boolean;\n  delay?: number;\n}\n\nconst isTouchEvent = (ev: Event): ev is TouchEvent => {\n  return 'touches' in ev;\n};\n\nconst preventDefault = (ev: Event) => {\n  if (!isTouchEvent(ev)) return;\n\n  if (ev.touches.length < 2 && ev.preventDefault) {\n    ev.preventDefault();\n  }\n};\n\nconst useLongPress = (\n  callback: (e: TouchEvent | MouseEvent) => void,\n  { isPreventDefault = true, delay = 300 }: Options = {}\n) => {\n  const timeout = useRef<ReturnType<typeof setTimeout>>();\n  const target = useRef<EventTarget>();\n\n  const start = useCallback(\n    (event: TouchEvent | MouseEvent) => {\n      // prevent ghost click on mobile devices\n      if (isPreventDefault && event.target) {\n        on(event.target, 'touchend', preventDefault, { passive: false });\n        target.current = event.target;\n      }\n      timeout.current = setTimeout(() => callback(event), delay);\n    },\n    [callback, delay, isPreventDefault]\n  );\n\n  const clear = useCallback(() => {\n    // clearTimeout and removeEventListener\n    timeout.current && clearTimeout(timeout.current);\n\n    if (isPreventDefault && target.current) {\n      off(target.current, 'touchend', preventDefault);\n    }\n  }, [isPreventDefault]);\n\n  return {\n    onMouseDown: (e: any) => start(e),\n    onTouchStart: (e: any) => start(e),\n    onMouseUp: clear,\n    onMouseLeave: clear,\n    onTouchEnd: clear,\n  } as const;\n};\n\nexport default useLongPress;\n"
  },
  {
    "path": "src/useMap.ts",
    "content": "import { useCallback, useMemo, useState } from 'react';\n\nexport interface StableActions<T extends object> {\n  set: <K extends keyof T>(key: K, value: T[K]) => void;\n  setAll: (newMap: T) => void;\n  remove: <K extends keyof T>(key: K) => void;\n  reset: () => void;\n}\n\nexport interface Actions<T extends object> extends StableActions<T> {\n  get: <K extends keyof T>(key: K) => T[K];\n}\n\nconst useMap = <T extends object = any>(initialMap: T = {} as T): [T, Actions<T>] => {\n  const [map, set] = useState<T>(initialMap);\n\n  const stableActions = useMemo<StableActions<T>>(\n    () => ({\n      set: (key, entry) => {\n        set((prevMap) => ({\n          ...prevMap,\n          [key]: entry,\n        }));\n      },\n      setAll: (newMap: T) => {\n        set(newMap);\n      },\n      remove: (key) => {\n        set((prevMap) => {\n          const { [key]: omit, ...rest } = prevMap;\n          return rest as T;\n        });\n      },\n      reset: () => set(initialMap),\n    }),\n    [set]\n  );\n\n  const utils = {\n    get: useCallback((key) => map[key], [map]),\n    ...stableActions,\n  } as Actions<T>;\n\n  return [map, utils];\n};\n\nexport default useMap;\n"
  },
  {
    "path": "src/useMeasure.ts",
    "content": "import { useMemo, useState } from 'react';\nimport useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect';\nimport { isBrowser, noop } from './misc/util';\n\nexport type UseMeasureRect = Pick<\n  DOMRectReadOnly,\n  'x' | 'y' | 'top' | 'left' | 'right' | 'bottom' | 'height' | 'width'\n>;\nexport type UseMeasureRef<E extends Element = Element> = (element: E) => void;\nexport type UseMeasureResult<E extends Element = Element> = [UseMeasureRef<E>, UseMeasureRect];\n\nconst defaultState: UseMeasureRect = {\n  x: 0,\n  y: 0,\n  width: 0,\n  height: 0,\n  top: 0,\n  left: 0,\n  bottom: 0,\n  right: 0,\n};\n\nfunction useMeasure<E extends Element = Element>(): UseMeasureResult<E> {\n  const [element, ref] = useState<E | null>(null);\n  const [rect, setRect] = useState<UseMeasureRect>(defaultState);\n\n  const observer = useMemo(\n    () =>\n      new (window as any).ResizeObserver((entries) => {\n        if (entries[0]) {\n          const { x, y, width, height, top, left, bottom, right } = entries[0].contentRect;\n          setRect({ x, y, width, height, top, left, bottom, right });\n        }\n      }),\n    []\n  );\n\n  useIsomorphicLayoutEffect(() => {\n    if (!element) return;\n    observer.observe(element);\n    return () => {\n      observer.disconnect();\n    };\n  }, [element]);\n\n  return [ref, rect];\n}\n\nexport default isBrowser && typeof (window as any).ResizeObserver !== 'undefined'\n  ? useMeasure\n  : ((() => [noop, defaultState]) as typeof useMeasure);\n"
  },
  {
    "path": "src/useMeasureDirty.ts",
    "content": "import { RefObject, useEffect, useRef, useState } from 'react';\nimport ResizeObserver from 'resize-observer-polyfill';\n\nexport interface ContentRect {\n  width: number;\n  height: number;\n  top: number;\n  right: number;\n  left: number;\n  bottom: number;\n}\n\nconst useMeasureDirty = (ref: RefObject<HTMLElement>): ContentRect => {\n  const frame = useRef(0);\n  const [rect, set] = useState({\n    width: 0,\n    height: 0,\n    top: 0,\n    left: 0,\n    bottom: 0,\n    right: 0,\n  });\n\n  const [observer] = useState(\n    () =>\n      new ResizeObserver((entries) => {\n        const entry = entries[0];\n\n        if (entry) {\n          cancelAnimationFrame(frame.current);\n\n          frame.current = requestAnimationFrame(() => {\n            if (ref.current) {\n              set(entry.contentRect);\n            }\n          });\n        }\n      })\n  );\n\n  useEffect(() => {\n    observer.disconnect();\n\n    if (ref.current) {\n      observer.observe(ref.current);\n    }\n  }, [ref]);\n\n  return rect;\n};\n\nexport default useMeasureDirty;\n"
  },
  {
    "path": "src/useMedia.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { isBrowser } from './misc/util';\n\nconst getInitialState = (query: string, defaultState?: boolean) => {\n  // Prevent a React hydration mismatch when a default value is provided by not defaulting to window.matchMedia(query).matches.\n  if (defaultState !== undefined) {\n    return defaultState;\n  }\n\n  if (isBrowser) {\n    return window.matchMedia(query).matches;\n  }\n\n  // A default value has not been provided, and you are rendering on the server, warn of a possible hydration mismatch when defaulting to false.\n  if (process.env.NODE_ENV !== 'production') {\n    console.warn(\n      '`useMedia` When server side rendering, defaultState should be defined to prevent a hydration mismatches.'\n    );\n  }\n\n  return false;\n};\n\nconst useMedia = (query: string, defaultState?: boolean) => {\n  const [state, setState] = useState(getInitialState(query, defaultState));\n\n  useEffect(() => {\n    let mounted = true;\n    const mql = window.matchMedia(query);\n    const onChange = () => {\n      if (!mounted) {\n        return;\n      }\n      setState(!!mql.matches);\n    };\n\n    mql.addEventListener('change', onChange);\n    setState(mql.matches);\n\n    return () => {\n      mounted = false;\n      mql.removeEventListener('change', onChange);\n    };\n  }, [query]);\n\n  return state;\n};\n\nexport default useMedia;\n"
  },
  {
    "path": "src/useMediaDevices.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { isNavigator, noop, off, on } from './misc/util';\n\nconst useMediaDevices = () => {\n  const [state, setState] = useState({});\n\n  useEffect(() => {\n    let mounted = true;\n\n    const onChange = () => {\n      navigator.mediaDevices\n        .enumerateDevices()\n        .then((devices) => {\n          if (mounted) {\n            setState({\n              devices: devices.map(({ deviceId, groupId, kind, label }) => ({\n                deviceId,\n                groupId,\n                kind,\n                label,\n              })),\n            });\n          }\n        })\n        .catch(noop);\n    };\n\n    on(navigator.mediaDevices, 'devicechange', onChange);\n    onChange();\n\n    return () => {\n      mounted = false;\n      off(navigator.mediaDevices, 'devicechange', onChange);\n    };\n  }, []);\n\n  return state;\n};\n\nconst useMediaDevicesMock = () => ({});\n\nexport default isNavigator && !!navigator.mediaDevices ? useMediaDevices : useMediaDevicesMock;\n"
  },
  {
    "path": "src/useMediatedState.ts",
    "content": "import { Dispatch, SetStateAction, useCallback, useRef, useState } from 'react';\n\nexport interface StateMediator<S = any> {\n  (newState: any): S;\n\n  (newState: any, dispatch: Dispatch<SetStateAction<S>>): void;\n}\n\nexport type UseMediatedStateReturn<S = any> = [S, Dispatch<SetStateAction<S>>];\n\nexport function useMediatedState<S = undefined>(\n  mediator: StateMediator<S | undefined>\n): UseMediatedStateReturn<S | undefined>;\nexport function useMediatedState<S = any>(\n  mediator: StateMediator<S>,\n  initialState: S\n): UseMediatedStateReturn<S>;\n\nexport function useMediatedState<S = any>(\n  mediator: StateMediator<S>,\n  initialState?: S\n): UseMediatedStateReturn<S> {\n  const mediatorFn = useRef(mediator);\n\n  const [state, setMediatedState] = useState<S>(initialState!);\n  const setState = useCallback(\n    (newState: any) => {\n      if (mediatorFn.current.length === 2) {\n        mediatorFn.current(newState, setMediatedState);\n      } else {\n        setMediatedState(mediatorFn.current(newState));\n      }\n    },\n    [state]\n  );\n\n  return [state, setState];\n}\n"
  },
  {
    "path": "src/useMethods.ts",
    "content": "import { Reducer, useMemo, useReducer } from 'react';\n\ntype Action = {\n  type: string;\n  payload?: any;\n};\n\ntype CreateMethods<M, T> = (state: T) => {\n  [P in keyof M]: (payload?: any) => T;\n};\n\ntype WrappedMethods<M> = {\n  [P in keyof M]: (...payload: any) => void;\n};\n\nconst useMethods = <M, T>(\n  createMethods: CreateMethods<M, T>,\n  initialState: T\n): [T, WrappedMethods<M>] => {\n  const reducer = useMemo<Reducer<T, Action>>(\n    () => (reducerState: T, action: Action) => {\n      return createMethods(reducerState)[action.type](...action.payload);\n    },\n    [createMethods]\n  );\n\n  const [state, dispatch] = useReducer<Reducer<T, Action>>(reducer, initialState);\n\n  const wrappedMethods: WrappedMethods<M> = useMemo(() => {\n    const actionTypes = Object.keys(createMethods(initialState));\n\n    return actionTypes.reduce((acc, type) => {\n      acc[type] = (...payload) => dispatch({ type, payload });\n      return acc;\n    }, {} as WrappedMethods<M>);\n  }, [createMethods, initialState]);\n\n  return [state, wrappedMethods];\n};\n\nexport default useMethods;\n"
  },
  {
    "path": "src/useMotion.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { off, on } from './misc/util';\n\nexport interface MotionSensorState {\n  acceleration: {\n    x: number | null;\n    y: number | null;\n    z: number | null;\n  };\n  accelerationIncludingGravity: {\n    x: number | null;\n    y: number | null;\n    z: number | null;\n  };\n  rotationRate: {\n    alpha: number | null;\n    beta: number | null;\n    gamma: number | null;\n  };\n  interval: number | null;\n}\n\nconst defaultState: MotionSensorState = {\n  acceleration: {\n    x: null,\n    y: null,\n    z: null,\n  },\n  accelerationIncludingGravity: {\n    x: null,\n    y: null,\n    z: null,\n  },\n  rotationRate: {\n    alpha: null,\n    beta: null,\n    gamma: null,\n  },\n  interval: 16,\n};\n\nconst useMotion = (initialState: MotionSensorState = defaultState) => {\n  const [state, setState] = useState(initialState);\n\n  useEffect(() => {\n    const handler = (event) => {\n      const { acceleration, accelerationIncludingGravity, rotationRate, interval } = event;\n\n      setState({\n        acceleration: {\n          x: acceleration.x,\n          y: acceleration.y,\n          z: acceleration.z,\n        },\n        accelerationIncludingGravity: {\n          x: accelerationIncludingGravity.x,\n          y: accelerationIncludingGravity.y,\n          z: accelerationIncludingGravity.z,\n        },\n        rotationRate: {\n          alpha: rotationRate.alpha,\n          beta: rotationRate.beta,\n          gamma: rotationRate.gamma,\n        },\n        interval,\n      });\n    };\n\n    on(window, 'devicemotion', handler);\n\n    return () => {\n      off(window, 'devicemotion', handler);\n    };\n  }, []);\n\n  return state;\n};\n\nexport default useMotion;\n"
  },
  {
    "path": "src/useMount.ts",
    "content": "import useEffectOnce from './useEffectOnce';\n\nconst useMount = (fn: () => void) => {\n  useEffectOnce(() => {\n    fn();\n  });\n};\n\nexport default useMount;\n"
  },
  {
    "path": "src/useMountedState.ts",
    "content": "import { useCallback, useEffect, useRef } from 'react';\n\nexport default function useMountedState(): () => boolean {\n  const mountedRef = useRef<boolean>(false);\n  const get = useCallback(() => mountedRef.current, []);\n\n  useEffect(() => {\n    mountedRef.current = true;\n\n    return () => {\n      mountedRef.current = false;\n    };\n  }, []);\n\n  return get;\n}\n"
  },
  {
    "path": "src/useMouse.ts",
    "content": "import { RefObject, useEffect } from 'react';\n\nimport useRafState from './useRafState';\nimport { off, on } from './misc/util';\n\nexport interface State {\n  docX: number;\n  docY: number;\n  posX: number;\n  posY: number;\n  elX: number;\n  elY: number;\n  elH: number;\n  elW: number;\n}\n\nconst useMouse = (ref: RefObject<Element>): State => {\n  if (process.env.NODE_ENV === 'development') {\n    if (typeof ref !== 'object' || typeof ref.current === 'undefined') {\n      console.error('useMouse expects a single ref argument.');\n    }\n  }\n\n  const [state, setState] = useRafState<State>({\n    docX: 0,\n    docY: 0,\n    posX: 0,\n    posY: 0,\n    elX: 0,\n    elY: 0,\n    elH: 0,\n    elW: 0,\n  });\n\n  useEffect(() => {\n    const moveHandler = (event: MouseEvent) => {\n      if (ref && ref.current) {\n        const { left, top, width: elW, height: elH } = ref.current.getBoundingClientRect();\n        const posX = left + window.pageXOffset;\n        const posY = top + window.pageYOffset;\n        const elX = event.pageX - posX;\n        const elY = event.pageY - posY;\n\n        setState({\n          docX: event.pageX,\n          docY: event.pageY,\n          posX,\n          posY,\n          elX,\n          elY,\n          elH,\n          elW,\n        });\n      }\n    };\n\n    on(document, 'mousemove', moveHandler);\n\n    return () => {\n      off(document, 'mousemove', moveHandler);\n    };\n  }, [ref]);\n\n  return state;\n};\n\nexport default useMouse;\n"
  },
  {
    "path": "src/useMouseHovered.ts",
    "content": "import { RefObject } from 'react';\nimport useHoverDirty from './useHoverDirty';\nimport useMouse, { State } from './useMouse';\n\nexport interface UseMouseHoveredOptions {\n  whenHovered?: boolean;\n  bound?: boolean;\n}\n\nconst nullRef = { current: null };\n\nconst useMouseHovered = (ref: RefObject<Element>, options: UseMouseHoveredOptions = {}): State => {\n  const whenHovered = !!options.whenHovered;\n  const bound = !!options.bound;\n\n  const isHovered = useHoverDirty(ref, whenHovered);\n  const state = useMouse(whenHovered && !isHovered ? nullRef : ref);\n\n  if (bound) {\n    state.elX = Math.max(0, Math.min(state.elX, state.elW));\n    state.elY = Math.max(0, Math.min(state.elY, state.elH));\n  }\n\n  return state;\n};\n\nexport default useMouseHovered;\n"
  },
  {
    "path": "src/useMouseWheel.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { off, on } from './misc/util';\n\nexport default () => {\n  const [mouseWheelScrolled, setMouseWheelScrolled] = useState(0);\n  useEffect(() => {\n    const updateScroll = (e: MouseWheelEvent) => {\n      setMouseWheelScrolled(e.deltaY + mouseWheelScrolled);\n    };\n    on(window, 'wheel', updateScroll, false);\n    return () => off(window, 'wheel', updateScroll);\n  });\n  return mouseWheelScrolled;\n};\n"
  },
  {
    "path": "src/useMultiStateValidator.ts",
    "content": "import { useCallback, useEffect, useRef, useState } from 'react';\nimport { StateValidator, UseStateValidatorReturn, ValidityState } from './useStateValidator';\n\nexport type MultiStateValidatorStates = any[] | { [p: string]: any } | { [p: number]: any };\nexport type MultiStateValidator<V extends ValidityState, S extends MultiStateValidatorStates> =\n  StateValidator<V, S>;\n\nexport function useMultiStateValidator<\n  V extends ValidityState,\n  S extends MultiStateValidatorStates\n>(\n  states: S,\n  validator: MultiStateValidator<V, S>,\n  initialValidity: V = [undefined] as V\n): UseStateValidatorReturn<V> {\n  if (typeof states !== 'object') {\n    throw new Error('states expected to be an object or array, got ' + typeof states);\n  }\n\n  const validatorInner = useRef(validator);\n  const statesInner = useRef(states);\n\n  validatorInner.current = validator;\n  statesInner.current = states;\n\n  const [validity, setValidity] = useState(initialValidity as V);\n\n  const validate = useCallback(() => {\n    if (validatorInner.current.length >= 2) {\n      validatorInner.current(statesInner.current, setValidity);\n    } else {\n      setValidity(validatorInner.current(statesInner.current));\n    }\n  }, [setValidity]);\n\n  useEffect(() => {\n    validate();\n  }, Object.values(states));\n\n  return [validity, validate];\n}\n"
  },
  {
    "path": "src/useNetworkState.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { isNavigator, off, on } from './misc/util';\nimport { IHookStateInitAction } from './misc/hookState';\n\nexport interface INetworkInformation extends EventTarget {\n  readonly downlink: number;\n  readonly downlinkMax: number;\n  readonly effectiveType: 'slow-2g' | '2g' | '3g' | '4g';\n  readonly rtt: number;\n  readonly saveData: boolean;\n  readonly type:\n    | 'bluetooth'\n    | 'cellular'\n    | 'ethernet'\n    | 'none'\n    | 'wifi'\n    | 'wimax'\n    | 'other'\n    | 'unknown';\n\n  onChange: (event: Event) => void;\n}\n\nexport interface IUseNetworkState {\n  /**\n   * @desc Whether browser connected to the network or not.\n   */\n  online: boolean | undefined;\n  /**\n   * @desc Previous value of `online` property. Helps to identify if browser\n   * just connected or lost connection.\n   */\n  previous: boolean | undefined;\n  /**\n   * @desc The {Date} object pointing to the moment when state change occurred.\n   */\n  since: Date | undefined;\n  /**\n   * @desc Effective bandwidth estimate in megabits per second, rounded to the\n   * nearest multiple of 25 kilobits per seconds.\n   */\n  downlink: INetworkInformation['downlink'] | undefined;\n  /**\n   * @desc Maximum downlink speed, in megabits per second (Mbps), for the\n   * underlying connection technology\n   */\n  downlinkMax: INetworkInformation['downlinkMax'] | undefined;\n  /**\n   * @desc Effective type of the connection meaning one of 'slow-2g', '2g', '3g', or '4g'.\n   * This value is determined using a combination of recently observed round-trip time\n   * and downlink values.\n   */\n  effectiveType: INetworkInformation['effectiveType'] | undefined;\n  /**\n   * @desc Estimated effective round-trip time of the current connection, rounded\n   * to the nearest multiple of 25 milliseconds\n   */\n  rtt: INetworkInformation['rtt'] | undefined;\n  /**\n   * @desc {true} if the user has set a reduced data usage option on the user agent.\n   */\n  saveData: INetworkInformation['saveData'] | undefined;\n  /**\n   * @desc The type of connection a device is using to communicate with the network.\n   * It will be one of the following values:\n   *  - bluetooth\n   *  - cellular\n   *  - ethernet\n   *  - none\n   *  - wifi\n   *  - wimax\n   *  - other\n   *  - unknown\n   */\n  type: INetworkInformation['type'] | undefined;\n}\n\nconst nav:\n  | (Navigator &\n      Partial<Record<'connection' | 'mozConnection' | 'webkitConnection', INetworkInformation>>)\n  | undefined = isNavigator ? navigator : undefined;\nconst conn: INetworkInformation | undefined =\n  nav && (nav.connection || nav.mozConnection || nav.webkitConnection);\n\nfunction getConnectionState(previousState?: IUseNetworkState): IUseNetworkState {\n  const online = nav?.onLine;\n  const previousOnline = previousState?.online;\n\n  return {\n    online,\n    previous: previousOnline,\n    since: online !== previousOnline ? new Date() : previousState?.since,\n    downlink: conn?.downlink,\n    downlinkMax: conn?.downlinkMax,\n    effectiveType: conn?.effectiveType,\n    rtt: conn?.rtt,\n    saveData: conn?.saveData,\n    type: conn?.type,\n  };\n}\n\nexport default function useNetworkState(\n  initialState?: IHookStateInitAction<IUseNetworkState>\n): IUseNetworkState {\n  const [state, setState] = useState(initialState ?? getConnectionState);\n\n  useEffect(() => {\n    const handleStateChange = () => {\n      setState(getConnectionState);\n    };\n\n    on(window, 'online', handleStateChange, { passive: true });\n    on(window, 'offline', handleStateChange, { passive: true });\n\n    if (conn) {\n      on(conn, 'change', handleStateChange, { passive: true });\n    }\n\n    return () => {\n      off(window, 'online', handleStateChange);\n      off(window, 'offline', handleStateChange);\n\n      if (conn) {\n        off(conn, 'change', handleStateChange);\n      }\n    };\n  }, []);\n\n  return state;\n}\n"
  },
  {
    "path": "src/useNumber.ts",
    "content": "import useNumber from './useCounter';\n\nexport default useNumber;\n"
  },
  {
    "path": "src/useObservable.ts",
    "content": "import { useState } from 'react';\nimport useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect';\n\nexport interface Observable<T> {\n  subscribe: (listener: (value: T) => void) => {\n    unsubscribe: () => void;\n  };\n}\n\nfunction useObservable<T>(observable$: Observable<T>): T | undefined;\nfunction useObservable<T>(observable$: Observable<T>, initialValue: T): T;\nfunction useObservable<T>(observable$: Observable<T>, initialValue?: T): T | undefined {\n  const [value, update] = useState<T | undefined>(initialValue);\n\n  useIsomorphicLayoutEffect(() => {\n    const s = observable$.subscribe(update);\n    return () => s.unsubscribe();\n  }, [observable$]);\n\n  return value;\n}\n\nexport default useObservable;\n"
  },
  {
    "path": "src/useOrientation.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { off, on } from './misc/util';\n\nexport interface OrientationState {\n  angle: number;\n  type: string;\n}\n\nconst defaultState: OrientationState = {\n  angle: 0,\n  type: 'landscape-primary',\n};\n\nconst useOrientation = (initialState: OrientationState = defaultState) => {\n  const [state, setState] = useState(initialState);\n\n  useEffect(() => {\n    const screen = window.screen;\n    let mounted = true;\n\n    const onChange = () => {\n      if (mounted) {\n        const { orientation } = screen as any;\n\n        if (orientation) {\n          const { angle, type } = orientation;\n          setState({ angle, type });\n        } else if (window.orientation !== undefined) {\n          setState({\n            angle: typeof window.orientation === 'number' ? window.orientation : 0,\n            type: '',\n          });\n        } else {\n          setState(initialState);\n        }\n      }\n    };\n\n    on(window, 'orientationchange', onChange);\n    onChange();\n\n    return () => {\n      mounted = false;\n      off(window, 'orientationchange', onChange);\n    };\n  }, []);\n\n  return state;\n};\n\nexport default useOrientation;\n"
  },
  {
    "path": "src/usePageLeave.ts",
    "content": "import { useEffect } from 'react';\nimport { off, on } from './misc/util';\n\nconst usePageLeave = (onPageLeave, args = []) => {\n  useEffect(() => {\n    if (!onPageLeave) {\n      return;\n    }\n\n    const handler = (event) => {\n      event = event ? event : (window.event as any);\n      const from = event.relatedTarget || event.toElement;\n      if (!from || (from as any).nodeName === 'HTML') {\n        onPageLeave();\n      }\n    };\n\n    on(document, 'mouseout', handler);\n    return () => {\n      off(document, 'mouseout', handler);\n    };\n  }, args);\n};\n\nexport default usePageLeave;\n"
  },
  {
    "path": "src/usePermission.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { noop, off, on } from './misc/util';\n\nexport type IState = PermissionState | '';\n\ninterface IPushPermissionDescriptor extends PermissionDescriptor {\n  name: 'push';\n  userVisibleOnly?: boolean;\n}\n\ninterface IMidiPermissionDescriptor extends PermissionDescriptor {\n  name: 'midi';\n  sysex?: boolean;\n}\n\ninterface IDevicePermissionDescriptor extends PermissionDescriptor {\n  name: 'camera' | 'microphone' | 'speaker';\n  deviceId?: string;\n}\n\nexport type IPermissionDescriptor =\n  | PermissionDescriptor\n  | IPushPermissionDescriptor\n  | IMidiPermissionDescriptor\n  | IDevicePermissionDescriptor;\n\n// const usePermission = <T extends PermissionDescriptor>(permissionDesc: T): IState => {\nconst usePermission = (permissionDesc: IPermissionDescriptor): IState => {\n  const [state, setState] = useState<IState>('');\n\n  useEffect(() => {\n    let mounted = true;\n    let permissionStatus: PermissionStatus | null = null;\n\n    const onChange = () => {\n      if (!mounted) {\n        return;\n      }\n      setState(() => permissionStatus?.state ?? '');\n    };\n\n    navigator.permissions\n      .query(permissionDesc)\n      .then((status) => {\n        permissionStatus = status;\n        on(permissionStatus, 'change', onChange);\n        onChange();\n      })\n      .catch(noop);\n\n    return () => {\n      permissionStatus && off(permissionStatus, 'change', onChange);\n      mounted = false;\n      permissionStatus = null;\n    };\n  }, [permissionDesc]);\n\n  return state;\n};\n\nexport default usePermission;\n"
  },
  {
    "path": "src/usePinchZoom.ts",
    "content": "import { RefObject, useEffect, useMemo, useState } from 'react';\n\nexport type CacheRef = {\n  prevDiff: number;\n  evCache: Array<PointerEvent>;\n};\n\nexport enum ZoomState {\n  'ZOOMING_IN' = 'ZOOMING_IN',\n  'ZOOMING_OUT' = 'ZOOMING_OUT',\n}\n\nexport type ZoomStateType = ZoomState.ZOOMING_IN | ZoomState.ZOOMING_OUT;\n\nconst usePinchZoom = (ref: RefObject<HTMLElement>) => {\n  const cacheRef = useMemo<CacheRef>(\n    () => ({\n      evCache: [],\n      prevDiff: -1,\n    }),\n    [ref.current]\n  );\n\n  const [zoomingState, setZoomingState] = useState<[ZoomStateType, number]>();\n\n  const pointermove_handler = (ev: PointerEvent) => {\n    // This function implements a 2-pointer horizontal pinch/zoom gesture.\n    //\n    // If the distance between the two pointers has increased (zoom in),\n    // the target element's background is changed to 'pink' and if the\n    // distance is decreasing (zoom out), the color is changed to 'lightblue'.\n    //\n    // This function sets the target element's border to 'dashed' to visually\n    // indicate the pointer's target received a move event.\n    // Find this event in the cache and update its record with this event\n    for (let i = 0; i < cacheRef.evCache.length; i++) {\n      if (ev.pointerId == cacheRef.evCache[i].pointerId) {\n        cacheRef.evCache[i] = ev;\n        break;\n      }\n    }\n\n    // If two pointers are down, check for pinch gestures\n    if (cacheRef.evCache.length == 2) {\n      // console.log(prevDiff)\n      // Calculate the distance between the two pointers\n      const curDiff = Math.abs(cacheRef.evCache[0].clientX - cacheRef.evCache[1].clientX);\n\n      if (cacheRef.prevDiff > 0) {\n        if (curDiff > cacheRef.prevDiff) {\n          // The distance between the two pointers has increased\n          setZoomingState([ZoomState.ZOOMING_IN, curDiff]);\n        }\n        if (curDiff < cacheRef.prevDiff) {\n          // The distance between the two pointers has decreased\n          setZoomingState([ZoomState.ZOOMING_OUT, curDiff]);\n        }\n      }\n\n      // Cache the distance for the next move event\n      cacheRef.prevDiff = curDiff;\n    }\n  };\n\n  const pointerdown_handler = (ev: PointerEvent) => {\n    // The pointerdown event signals the start of a touch interaction.\n    // This event is cached to support 2-finger gestures\n    cacheRef.evCache.push(ev);\n    // console.log('pointerDown', ev);\n  };\n\n  const pointerup_handler = (ev: PointerEvent) => {\n    // Remove this pointer from the cache and reset the target's\n    // background and border\n    remove_event(ev);\n\n    // If the number of pointers down is less than two then reset diff tracker\n    if (cacheRef.evCache.length < 2) {\n      cacheRef.prevDiff = -1;\n    }\n  };\n\n  const remove_event = (ev: PointerEvent) => {\n    // Remove this event from the target's cache\n    for (let i = 0; i < cacheRef.evCache.length; i++) {\n      if (cacheRef.evCache[i].pointerId == ev.pointerId) {\n        cacheRef.evCache.splice(i, 1);\n        break;\n      }\n    }\n  };\n\n  useEffect(() => {\n    if (ref?.current) {\n      ref.current.onpointerdown = pointerdown_handler;\n      ref.current.onpointermove = pointermove_handler;\n      ref.current.onpointerup = pointerup_handler;\n      ref.current.onpointercancel = pointerup_handler;\n      ref.current.onpointerout = pointerup_handler;\n      ref.current.onpointerleave = pointerup_handler;\n    }\n  }, [ref?.current]);\n\n  return zoomingState\n    ? { zoomingState: zoomingState[0], pinchState: zoomingState[1] }\n    : { zoomingState: null, pinchState: 0 };\n};\n\nexport default usePinchZoom;\n"
  },
  {
    "path": "src/usePrevious.ts",
    "content": "import { useEffect, useRef } from 'react';\n\nexport default function usePrevious<T>(state: T): T | undefined {\n  const ref = useRef<T>();\n\n  useEffect(() => {\n    ref.current = state;\n  });\n\n  return ref.current;\n}\n"
  },
  {
    "path": "src/usePreviousDistinct.ts",
    "content": "import { useRef } from 'react';\nimport { useFirstMountState } from './useFirstMountState';\n\nexport type Predicate<T> = (prev: T | undefined, next: T) => boolean;\n\nconst strictEquals = <T>(prev: T | undefined, next: T) => prev === next;\n\nexport default function usePreviousDistinct<T>(\n  value: T,\n  compare: Predicate<T> = strictEquals\n): T | undefined {\n  const prevRef = useRef<T>();\n  const curRef = useRef<T>(value);\n  const isFirstMount = useFirstMountState();\n\n  if (!isFirstMount && !compare(curRef.current, value)) {\n    prevRef.current = curRef.current;\n    curRef.current = value;\n  }\n\n  return prevRef.current;\n}\n"
  },
  {
    "path": "src/usePromise.ts",
    "content": "import { useCallback } from 'react';\nimport useMountedState from './useMountedState';\n\nexport type UsePromise = () => <T>(promise: Promise<T>) => Promise<T>;\n\nconst usePromise: UsePromise = () => {\n  const isMounted = useMountedState();\n  return useCallback(\n    (promise: Promise<any>) =>\n      new Promise<any>((resolve, reject) => {\n        const onValue = (value) => {\n          isMounted() && resolve(value);\n        };\n        const onError = (error) => {\n          isMounted() && reject(error);\n        };\n        promise.then(onValue, onError);\n      }),\n    []\n  );\n};\n\nexport default usePromise;\n"
  },
  {
    "path": "src/useQueue.ts",
    "content": "import { useState } from 'react';\n\nexport interface QueueMethods<T> {\n  add: (item: T) => void;\n  remove: () => T;\n  first: T;\n  last: T;\n  size: number;\n}\n\nconst useQueue = <T>(initialValue: T[] = []): QueueMethods<T> => {\n  const [state, set] = useState(initialValue);\n  return {\n    add: (value) => {\n      set((queue) => [...queue, value]);\n    },\n    remove: () => {\n      let result;\n      set(([first, ...rest]) => {\n        result = first;\n        return rest;\n      });\n      return result;\n    },\n    get first() {\n      return state[0];\n    },\n    get last() {\n      return state[state.length - 1];\n    },\n    get size() {\n      return state.length;\n    },\n  };\n};\n\nexport default useQueue;\n"
  },
  {
    "path": "src/useRaf.ts",
    "content": "import { useState } from 'react';\nimport useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect';\n\nconst useRaf = (ms: number = 1e12, delay: number = 0): number => {\n  const [elapsed, set] = useState<number>(0);\n\n  useIsomorphicLayoutEffect(() => {\n    let raf;\n    let timerStop;\n    let start;\n\n    const onFrame = () => {\n      const time = Math.min(1, (Date.now() - start) / ms);\n      set(time);\n      loop();\n    };\n    const loop = () => {\n      raf = requestAnimationFrame(onFrame);\n    };\n    const onStart = () => {\n      timerStop = setTimeout(() => {\n        cancelAnimationFrame(raf);\n        set(1);\n      }, ms);\n      start = Date.now();\n      loop();\n    };\n    const timerDelay = setTimeout(onStart, delay);\n\n    return () => {\n      clearTimeout(timerStop);\n      clearTimeout(timerDelay);\n      cancelAnimationFrame(raf);\n    };\n  }, [ms, delay]);\n\n  return elapsed;\n};\n\nexport default useRaf;\n"
  },
  {
    "path": "src/useRafLoop.ts",
    "content": "import { useCallback, useEffect, useMemo, useRef } from 'react';\n\nexport type RafLoopReturns = [() => void, () => void, () => boolean];\n\nexport default function useRafLoop(\n  callback: FrameRequestCallback,\n  initiallyActive = true\n): RafLoopReturns {\n  const raf = useRef<number | null>(null);\n  const rafActivity = useRef<boolean>(false);\n  const rafCallback = useRef(callback);\n  rafCallback.current = callback;\n\n  const step = useCallback((time: number) => {\n    if (rafActivity.current) {\n      rafCallback.current(time);\n      raf.current = requestAnimationFrame(step);\n    }\n  }, []);\n\n  const result = useMemo(\n    () =>\n      [\n        () => {\n          // stop\n          if (rafActivity.current) {\n            rafActivity.current = false;\n            raf.current && cancelAnimationFrame(raf.current);\n          }\n        },\n        () => {\n          // start\n          if (!rafActivity.current) {\n            rafActivity.current = true;\n            raf.current = requestAnimationFrame(step);\n          }\n        },\n        (): boolean => rafActivity.current, // isActive\n        // eslint-disable-next-line react-hooks/exhaustive-deps\n      ] as RafLoopReturns,\n    []\n  );\n\n  useEffect(() => {\n    if (initiallyActive) {\n      result[1]();\n    }\n\n    return result[0];\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []);\n\n  return result;\n}\n"
  },
  {
    "path": "src/useRafState.ts",
    "content": "import { Dispatch, SetStateAction, useCallback, useRef, useState } from 'react';\n\nimport useUnmount from './useUnmount';\n\nconst useRafState = <S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>] => {\n  const frame = useRef(0);\n  const [state, setState] = useState(initialState);\n\n  const setRafState = useCallback((value: S | ((prevState: S) => S)) => {\n    cancelAnimationFrame(frame.current);\n\n    frame.current = requestAnimationFrame(() => {\n      setState(value);\n    });\n  }, []);\n\n  useUnmount(() => {\n    cancelAnimationFrame(frame.current);\n  });\n\n  return [state, setRafState];\n};\n\nexport default useRafState;\n"
  },
  {
    "path": "src/useRendersCount.ts",
    "content": "import { useRef } from 'react';\n\nexport function useRendersCount(): number {\n  return ++useRef(0).current;\n}\n"
  },
  {
    "path": "src/useScratch.ts",
    "content": "import { cloneElement, FC, useEffect, useRef, useState } from 'react';\nimport { render } from 'react-universal-interface';\nimport useLatest from './useLatest';\nimport { noop, off, on } from './misc/util';\n\nexport interface ScratchSensorParams {\n  disabled?: boolean;\n  onScratch?: (state: ScratchSensorState) => void;\n  onScratchStart?: (state: ScratchSensorState) => void;\n  onScratchEnd?: (state: ScratchSensorState) => void;\n}\n\nexport interface ScratchSensorState {\n  isScratching: boolean;\n  start?: number;\n  end?: number;\n  x?: number;\n  y?: number;\n  dx?: number;\n  dy?: number;\n  docX?: number;\n  docY?: number;\n  posX?: number;\n  posY?: number;\n  elH?: number;\n  elW?: number;\n  elX?: number;\n  elY?: number;\n}\n\nconst useScratch = (\n  params: ScratchSensorParams = {}\n): [(el: HTMLElement | null) => void, ScratchSensorState] => {\n  const { disabled } = params;\n  const paramsRef = useLatest(params);\n  const [state, setState] = useState<ScratchSensorState>({ isScratching: false });\n  const refState = useRef<ScratchSensorState>(state);\n  const refScratching = useRef<boolean>(false);\n  const refAnimationFrame = useRef<any>(null);\n  const [el, setEl] = useState<HTMLElement | null>(null);\n  useEffect(() => {\n    if (disabled) return;\n    if (!el) return;\n\n    const onMoveEvent = (docX, docY) => {\n      cancelAnimationFrame(refAnimationFrame.current);\n      refAnimationFrame.current = requestAnimationFrame(() => {\n        const { left, top } = el.getBoundingClientRect();\n        const elX = left + window.scrollX;\n        const elY = top + window.scrollY;\n        const x = docX - elX;\n        const y = docY - elY;\n        setState((oldState) => {\n          const newState = {\n            ...oldState,\n            dx: x - (oldState.x || 0),\n            dy: y - (oldState.y || 0),\n            end: Date.now(),\n            isScratching: true,\n          };\n          refState.current = newState;\n          (paramsRef.current.onScratch || noop)(newState);\n          return newState;\n        });\n      });\n    };\n\n    const onMouseMove = (event) => {\n      onMoveEvent(event.pageX, event.pageY);\n    };\n\n    const onTouchMove = (event) => {\n      onMoveEvent(event.changedTouches[0].pageX, event.changedTouches[0].pageY);\n    };\n\n    let onMouseUp;\n    let onTouchEnd;\n\n    const stopScratching = () => {\n      if (!refScratching.current) return;\n      refScratching.current = false;\n      refState.current = { ...refState.current, isScratching: false };\n      (paramsRef.current.onScratchEnd || noop)(refState.current);\n      setState({ isScratching: false });\n      off(window, 'mousemove', onMouseMove);\n      off(window, 'touchmove', onTouchMove);\n      off(window, 'mouseup', onMouseUp);\n      off(window, 'touchend', onTouchEnd);\n    };\n\n    onMouseUp = stopScratching;\n    onTouchEnd = stopScratching;\n\n    const startScratching = (docX, docY) => {\n      if (!refScratching.current) return;\n      const { left, top } = el.getBoundingClientRect();\n      const elX = left + window.scrollX;\n      const elY = top + window.scrollY;\n      const x = docX - elX;\n      const y = docY - elY;\n      const time = Date.now();\n      const newState = {\n        isScratching: true,\n        start: time,\n        end: time,\n        docX,\n        docY,\n        x,\n        y,\n        dx: 0,\n        dy: 0,\n        elH: el.offsetHeight,\n        elW: el.offsetWidth,\n        elX,\n        elY,\n      };\n      refState.current = newState;\n      (paramsRef.current.onScratchStart || noop)(newState);\n      setState(newState);\n      on(window, 'mousemove', onMouseMove);\n      on(window, 'touchmove', onTouchMove);\n      on(window, 'mouseup', onMouseUp);\n      on(window, 'touchend', onTouchEnd);\n    };\n\n    const onMouseDown = (event) => {\n      refScratching.current = true;\n      startScratching(event.pageX, event.pageY);\n    };\n\n    const onTouchStart = (event) => {\n      refScratching.current = true;\n      startScratching(event.changedTouches[0].pageX, event.changedTouches[0].pageY);\n    };\n\n    on(el, 'mousedown', onMouseDown);\n    on(el, 'touchstart', onTouchStart);\n\n    return () => {\n      off(el, 'mousedown', onMouseDown);\n      off(el, 'touchstart', onTouchStart);\n      off(window, 'mousemove', onMouseMove);\n      off(window, 'touchmove', onTouchMove);\n      off(window, 'mouseup', onMouseUp);\n      off(window, 'touchend', onTouchEnd);\n\n      if (refAnimationFrame.current) cancelAnimationFrame(refAnimationFrame.current);\n      refAnimationFrame.current = null;\n\n      refScratching.current = false;\n      refState.current = { isScratching: false };\n      setState(refState.current);\n    };\n  }, [el, disabled, paramsRef]);\n\n  return [setEl, state];\n};\n\nexport interface ScratchSensorProps extends ScratchSensorParams {\n  children: (\n    state: ScratchSensorState,\n    ref: (el: HTMLElement | null) => void\n  ) => React.ReactElement<any>;\n}\n\nexport const ScratchSensor: FC<ScratchSensorProps> = (props) => {\n  const { children, ...params } = props;\n  const [ref, state] = useScratch(params);\n  const element = render(props, state);\n  return cloneElement(element, {\n    ...element.props,\n    ref: (el) => {\n      if (element.props.ref) {\n        if (typeof element.props.ref === 'object') element.props.ref.current = el;\n        if (typeof element.props.ref === 'function') element.props.ref(el);\n      }\n      ref(el);\n    },\n  });\n};\n\nexport default useScratch;\n"
  },
  {
    "path": "src/useScroll.ts",
    "content": "import { RefObject, useEffect } from 'react';\n\nimport useRafState from './useRafState';\nimport { off, on } from './misc/util';\n\nexport interface State {\n  x: number;\n  y: number;\n}\n\nconst useScroll = (ref: RefObject<HTMLElement>): State => {\n  if (process.env.NODE_ENV === 'development') {\n    if (typeof ref !== 'object' || typeof ref.current === 'undefined') {\n      console.error('`useScroll` expects a single ref argument.');\n    }\n  }\n\n  const [state, setState] = useRafState<State>({\n    x: 0,\n    y: 0,\n  });\n\n  useEffect(() => {\n    const handler = () => {\n      if (ref.current) {\n        setState({\n          x: ref.current.scrollLeft,\n          y: ref.current.scrollTop,\n        });\n      }\n    };\n\n    if (ref.current) {\n      on(ref.current, 'scroll', handler, {\n        capture: false,\n        passive: true,\n      });\n    }\n\n    return () => {\n      if (ref.current) {\n        off(ref.current, 'scroll', handler);\n      }\n    };\n  }, [ref]);\n\n  return state;\n};\n\nexport default useScroll;\n"
  },
  {
    "path": "src/useScrollbarWidth.ts",
    "content": "import { scrollbarWidth } from '@xobotyi/scrollbar-width';\nimport { useEffect, useState } from 'react';\n\nexport function useScrollbarWidth(): number | undefined {\n  const [sbw, setSbw] = useState(scrollbarWidth());\n\n  // this needed to ensure the scrollbar width in case hook called before the DOM is ready\n  useEffect(() => {\n    if (typeof sbw !== 'undefined') {\n      return;\n    }\n\n    const raf = requestAnimationFrame(() => {\n      setSbw(scrollbarWidth());\n    });\n\n    return () => cancelAnimationFrame(raf);\n  }, []);\n\n  return sbw;\n}\n"
  },
  {
    "path": "src/useScrolling.ts",
    "content": "import { RefObject, useEffect, useState } from 'react';\nimport { off, on } from './misc/util';\n\nconst useScrolling = (ref: RefObject<HTMLElement>): boolean => {\n  const [scrolling, setScrolling] = useState<boolean>(false);\n\n  useEffect(() => {\n    if (ref.current) {\n      let scrollingTimeout;\n\n      const handleScrollEnd = () => {\n        setScrolling(false);\n      };\n\n      const handleScroll = () => {\n        setScrolling(true);\n        clearTimeout(scrollingTimeout);\n        scrollingTimeout = setTimeout(() => handleScrollEnd(), 150);\n      };\n\n      on(ref.current, 'scroll', handleScroll, false);\n      return () => {\n        if (ref.current) {\n          off(ref.current, 'scroll', handleScroll, false);\n        }\n      };\n    }\n    return () => {};\n  }, [ref]);\n\n  return scrolling;\n};\n\nexport default useScrolling;\n"
  },
  {
    "path": "src/useSearchParam.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { isBrowser, off, on } from './misc/util';\n\nconst getValue = (search: string, param: string) => new URLSearchParams(search).get(param);\n\nexport type UseQueryParam = (param: string) => string | null;\n\nconst useSearchParam: UseQueryParam = (param) => {\n  const location = window.location;\n  const [value, setValue] = useState<string | null>(() => getValue(location.search, param));\n\n  useEffect(() => {\n    const onChange = () => {\n      setValue(getValue(location.search, param));\n    };\n\n    on(window, 'popstate', onChange);\n    on(window, 'pushstate', onChange);\n    on(window, 'replacestate', onChange);\n\n    return () => {\n      off(window, 'popstate', onChange);\n      off(window, 'pushstate', onChange);\n      off(window, 'replacestate', onChange);\n    };\n  }, []);\n\n  return value;\n};\n\nconst useSearchParamServer = () => null;\n\nexport default isBrowser ? useSearchParam : useSearchParamServer;\n"
  },
  {
    "path": "src/useSessionStorage.ts",
    "content": "import { useEffect, useState } from 'react';\nimport { isBrowser } from './misc/util';\n\nconst useSessionStorage = <T>(\n  key: string,\n  initialValue?: T,\n  raw?: boolean\n): [T, (value: T) => void] => {\n  if (!isBrowser) {\n    return [initialValue as T, () => {}];\n  }\n\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  const [state, setState] = useState<T>(() => {\n    try {\n      const sessionStorageValue = sessionStorage.getItem(key);\n      if (typeof sessionStorageValue !== 'string') {\n        sessionStorage.setItem(key, raw ? String(initialValue) : JSON.stringify(initialValue));\n        return initialValue;\n      } else {\n        return raw ? sessionStorageValue : JSON.parse(sessionStorageValue || 'null');\n      }\n    } catch {\n      // If user is in private mode or has storage restriction\n      // sessionStorage can throw. JSON.parse and JSON.stringify\n      // can throw, too.\n      return initialValue;\n    }\n  });\n\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  useEffect(() => {\n    try {\n      const serializedState = raw ? String(state) : JSON.stringify(state);\n      sessionStorage.setItem(key, serializedState);\n    } catch {\n      // If user is in private mode or has storage restriction\n      // sessionStorage can throw. Also JSON.stringify can throw.\n    }\n  });\n\n  return [state, setState];\n};\n\nexport default useSessionStorage;\n"
  },
  {
    "path": "src/useSet.ts",
    "content": "import { useCallback, useMemo, useState } from 'react';\n\nexport interface StableActions<K> {\n  add: (key: K) => void;\n  remove: (key: K) => void;\n  toggle: (key: K) => void;\n  reset: () => void;\n  clear: () => void;\n}\n\nexport interface Actions<K> extends StableActions<K> {\n  has: (key: K) => boolean;\n}\n\nconst useSet = <K>(initialSet = new Set<K>()): [Set<K>, Actions<K>] => {\n  const [set, setSet] = useState(initialSet);\n\n  const stableActions = useMemo<StableActions<K>>(() => {\n    const add = (item: K) => setSet((prevSet) => new Set([...Array.from(prevSet), item]));\n    const remove = (item: K) =>\n      setSet((prevSet) => new Set(Array.from(prevSet).filter((i) => i !== item)));\n    const toggle = (item: K) =>\n      setSet((prevSet) =>\n        prevSet.has(item)\n          ? new Set(Array.from(prevSet).filter((i) => i !== item))\n          : new Set([...Array.from(prevSet), item])\n      );\n\n    return { add, remove, toggle, reset: () => setSet(initialSet), clear: () => setSet(new Set()) };\n  }, [setSet]);\n\n  const utils = {\n    has: useCallback((item) => set.has(item), [set]),\n    ...stableActions,\n  } as Actions<K>;\n\n  return [set, utils];\n};\n\nexport default useSet;\n"
  },
  {
    "path": "src/useSetState.ts",
    "content": "import { useCallback, useState } from 'react';\n\nconst useSetState = <T extends object>(\n  initialState: T = {} as T\n): [T, (patch: Partial<T> | ((prevState: T) => Partial<T>)) => void] => {\n  const [state, set] = useState<T>(initialState);\n  const setState = useCallback((patch) => {\n    set((prevState) =>\n      Object.assign({}, prevState, patch instanceof Function ? patch(prevState) : patch)\n    );\n  }, []);\n\n  return [state, setState];\n};\n\nexport default useSetState;\n"
  },
  {
    "path": "src/useShallowCompareEffect.ts",
    "content": "import { DependencyList, EffectCallback } from 'react';\nimport { equal as isShallowEqual } from 'fast-shallow-equal';\nimport useCustomCompareEffect from './useCustomCompareEffect';\n\nconst isPrimitive = (val: any) => val !== Object(val);\nconst shallowEqualDepsList = (prevDeps: DependencyList, nextDeps: DependencyList) =>\n  prevDeps.every((dep, index) => isShallowEqual(dep, nextDeps[index]));\n\nconst useShallowCompareEffect = (effect: EffectCallback, deps: DependencyList) => {\n  if (process.env.NODE_ENV !== 'production') {\n    if (!(deps instanceof Array) || !deps.length) {\n      console.warn(\n        '`useShallowCompareEffect` should not be used with no dependencies. Use React.useEffect instead.'\n      );\n    }\n\n    if (deps.every(isPrimitive)) {\n      console.warn(\n        '`useShallowCompareEffect` should not be used with dependencies that are all primitive values. Use React.useEffect instead.'\n      );\n    }\n  }\n\n  useCustomCompareEffect(effect, deps, shallowEqualDepsList);\n};\n\nexport default useShallowCompareEffect;\n"
  },
  {
    "path": "src/useSize.tsx",
    "content": "import * as React from 'react';\nimport { isBrowser, off, on } from './misc/util';\n\nconst { useState, useEffect, useRef } = React;\n\nconst DRAF = (callback: () => void) => setTimeout(callback, 35);\n\nexport type Element = ((state: State) => React.ReactElement<any>) | React.ReactElement<any>;\n\nexport interface State {\n  width: number;\n  height: number;\n}\n\nconst useSize = (\n  element: Element,\n  { width = Infinity, height = Infinity }: Partial<State> = {}\n): [React.ReactElement<any>, State] => {\n  if (!isBrowser) {\n    return [\n      typeof element === 'function' ? element({ width, height }) : element,\n      { width, height },\n    ];\n  }\n\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  const [state, setState] = useState<State>({ width, height });\n\n  if (typeof element === 'function') {\n    element = element(state);\n  }\n\n  const style = element.props.style || {};\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  const ref = useRef<HTMLIFrameElement | null>(null);\n  let window: Window | null = null;\n  const setSize = () => {\n    const iframe = ref.current;\n    const size = iframe\n      ? {\n          width: iframe.offsetWidth,\n          height: iframe.offsetHeight,\n        }\n      : { width, height };\n\n    setState(size);\n  };\n  const onWindow = (windowToListenOn: Window) => {\n    on(windowToListenOn, 'resize', setSize);\n    DRAF(setSize);\n  };\n\n  // eslint-disable-next-line react-hooks/rules-of-hooks\n  useEffect(() => {\n    const iframe: HTMLIFrameElement | null = ref.current;\n\n    if (!iframe) {\n      // iframe will be undefined if component is already unmounted\n      return;\n    }\n\n    if (iframe.contentWindow) {\n      window = iframe.contentWindow!;\n      onWindow(window);\n    } else {\n      const onLoad = () => {\n        on(iframe, 'load', onLoad);\n        window = iframe.contentWindow!;\n        onWindow(window);\n      };\n\n      off(iframe, 'load', onLoad);\n    }\n\n    return () => {\n      if (window && window.removeEventListener) {\n        off(window, 'resize', setSize);\n      }\n    };\n  }, []);\n\n  style.position = 'relative';\n\n  const sized = React.cloneElement(\n    element,\n    { style },\n    ...[\n      React.createElement('iframe', {\n        ref,\n        style: {\n          background: 'transparent',\n          border: 'none',\n          height: '100%',\n          left: 0,\n          position: 'absolute',\n          top: 0,\n          width: '100%',\n          zIndex: -1,\n        },\n      }),\n      ...React.Children.toArray(element.props.children),\n    ]\n  );\n\n  return [sized, state];\n};\n\nexport default useSize;\n"
  },
  {
    "path": "src/useSlider.ts",
    "content": "import { CSSProperties, RefObject, useEffect, useRef } from 'react';\nimport { isBrowser, noop, off, on } from './misc/util';\nimport useMountedState from './useMountedState';\nimport useSetState from './useSetState';\n\nexport interface State {\n  isSliding: boolean;\n  value: number;\n}\n\nexport interface Options {\n  onScrub: (value: number) => void;\n  onScrubStart: () => void;\n  onScrubStop: (value: number) => void;\n  reverse: boolean;\n  styles: boolean | CSSProperties;\n  vertical?: boolean;\n}\n\nconst useSlider = (ref: RefObject<HTMLElement>, options: Partial<Options> = {}): State => {\n  const isMounted = useMountedState();\n  const isSliding = useRef(false);\n  const valueRef = useRef(0);\n  const frame = useRef(0);\n  const [state, setState] = useSetState<State>({\n    isSliding: false,\n    value: 0,\n  });\n\n  valueRef.current = state.value;\n\n  useEffect(() => {\n    if (isBrowser) {\n      const styles = options.styles === undefined ? true : options.styles;\n      const reverse = options.reverse === undefined ? false : options.reverse;\n\n      if (ref.current && styles) {\n        ref.current.style.userSelect = 'none';\n      }\n\n      const startScrubbing = () => {\n        if (!isSliding.current && isMounted()) {\n          (options.onScrubStart || noop)();\n          isSliding.current = true;\n          setState({ isSliding: true });\n          bindEvents();\n        }\n      };\n\n      const stopScrubbing = () => {\n        if (isSliding.current && isMounted()) {\n          (options.onScrubStop || noop)(valueRef.current);\n          isSliding.current = false;\n          setState({ isSliding: false });\n          unbindEvents();\n        }\n      };\n\n      const onMouseDown = (event: MouseEvent) => {\n        startScrubbing();\n        onMouseMove(event);\n      };\n      const onMouseMove = options.vertical\n        ? (event: MouseEvent) => onScrub(event.clientY)\n        : (event: MouseEvent) => onScrub(event.clientX);\n\n      const onTouchStart = (event: TouchEvent) => {\n        startScrubbing();\n        onTouchMove(event);\n      };\n      const onTouchMove = options.vertical\n        ? (event: TouchEvent) => onScrub(event.changedTouches[0].clientY)\n        : (event: TouchEvent) => onScrub(event.changedTouches[0].clientX);\n\n      const bindEvents = () => {\n        on(document, 'mousemove', onMouseMove);\n        on(document, 'mouseup', stopScrubbing);\n\n        on(document, 'touchmove', onTouchMove);\n        on(document, 'touchend', stopScrubbing);\n      };\n\n      const unbindEvents = () => {\n        off(document, 'mousemove', onMouseMove);\n        off(document, 'mouseup', stopScrubbing);\n\n        off(document, 'touchmove', onTouchMove);\n        off(document, 'touchend', stopScrubbing);\n      };\n\n      const onScrub = (clientXY: number) => {\n        cancelAnimationFrame(frame.current);\n\n        frame.current = requestAnimationFrame(() => {\n          if (isMounted() && ref.current) {\n            const rect = ref.current.getBoundingClientRect();\n            const pos = options.vertical ? rect.top : rect.left;\n            const length = options.vertical ? rect.height : rect.width;\n\n            // Prevent returning 0 when element is hidden by CSS\n            if (!length) {\n              return;\n            }\n\n            let value = (clientXY - pos) / length;\n\n            if (value > 1) {\n              value = 1;\n            } else if (value < 0) {\n              value = 0;\n            }\n\n            if (reverse) {\n              value = 1 - value;\n            }\n\n            setState({\n              value,\n            });\n\n            (options.onScrub || noop)(value);\n          }\n        });\n      };\n\n      on(ref.current, 'mousedown', onMouseDown);\n      on(ref.current, 'touchstart', onTouchStart);\n\n      return () => {\n        off(ref.current, 'mousedown', onMouseDown);\n        off(ref.current, 'touchstart', onTouchStart);\n      };\n    } else {\n      return undefined;\n    }\n  }, [ref, options.vertical]);\n\n  return state;\n};\n\nexport default useSlider;\n"
  },
  {
    "path": "src/useSpeech.ts",
    "content": "import { useCallback, useEffect, useRef, useState } from 'react';\n\ntype SpeechOptions = {\n  lang: string;\n  voice?: SpeechSynthesisVoice;\n  rate: number;\n  pitch: number;\n  volume: number;\n};\n\nexport type ISpeechOptions = Partial<SpeechOptions>;\n\nexport type VoiceInfo = Pick<SpeechSynthesisVoice, 'lang' | 'name'>;\n\nexport type ISpeechState = SpeechOptions & {\n  isPlaying: boolean;\n  status: string;\n  voiceInfo: VoiceInfo;\n};\n\nenum Status {\n  init,\n  play,\n  pause,\n  end,\n}\n\nconst useSpeech = (text: string, options: ISpeechOptions): ISpeechState => {\n  let mounted = useRef<boolean>(false);\n  const [state, setState] = useState<ISpeechState>(() => {\n    const { lang = 'default', name = '' } = options.voice || {};\n    return {\n      isPlaying: false,\n      status: Status[Status.init],\n      lang: options.lang || 'default',\n      voiceInfo: { lang, name },\n      rate: options.rate || 1,\n      pitch: options.pitch || 1,\n      volume: options.volume || 1,\n    };\n  });\n\n  const handlePlay = useCallback(() => {\n    if (!mounted.current) {\n      return;\n    }\n    setState((preState) => {\n      return { ...preState, isPlaying: true, status: Status[Status.play] };\n    });\n  }, []);\n\n  const handlePause = useCallback(() => {\n    if (!mounted.current) {\n      return;\n    }\n    setState((preState) => {\n      return { ...preState, isPlaying: false, status: Status[Status.pause] };\n    });\n  }, []);\n\n  const handleEnd = useCallback(() => {\n    if (!mounted.current) {\n      return;\n    }\n    setState((preState) => {\n      return { ...preState, isPlaying: false, status: Status[Status.end] };\n    });\n  }, []);\n\n  useEffect(() => {\n    mounted.current = true;\n    const utterance = new SpeechSynthesisUtterance(text);\n    options.lang && (utterance.lang = options.lang);\n    options.voice && (utterance.voice = options.voice);\n    utterance.rate = options.rate || 1;\n    utterance.pitch = options.pitch || 1;\n    utterance.volume = options.volume || 1;\n    utterance.onstart = handlePlay;\n    utterance.onpause = handlePause;\n    utterance.onresume = handlePlay;\n    utterance.onend = handleEnd;\n    window.speechSynthesis.speak(utterance);\n\n    return () => {\n      mounted.current = false;\n    };\n  }, []);\n\n  return state;\n};\n\nexport default useSpeech;\n"
  },
  {
    "path": "src/useSpring.ts",
    "content": "import { useEffect, useMemo, useState } from 'react';\nimport { Spring, SpringSystem } from 'rebound';\n\nconst useSpring = (targetValue: number = 0, tension: number = 50, friction: number = 3) => {\n  const [spring, setSpring] = useState<Spring | null>(null);\n  const [value, setValue] = useState<number>(targetValue);\n\n  // memoize listener to being able to unsubscribe later properly, otherwise\n  // listener fn will be different on each re-render and wouldn't unsubscribe properly.\n  const listener = useMemo(\n    () => ({\n      onSpringUpdate: (currentSpring) => {\n        const newValue = currentSpring.getCurrentValue();\n        setValue(newValue);\n      },\n    }),\n    []\n  );\n\n  useEffect(() => {\n    if (!spring) {\n      const newSpring = new SpringSystem().createSpring(tension, friction);\n      newSpring.setCurrentValue(targetValue);\n      setSpring(newSpring);\n      newSpring.addListener(listener);\n    }\n\n    return () => {\n      if (spring) {\n        spring.removeListener(listener);\n        setSpring(null);\n      }\n    };\n  }, [tension, friction, spring]);\n\n  useEffect(() => {\n    if (spring) {\n      spring.setEndValue(targetValue);\n    }\n  }, [targetValue]);\n\n  return value;\n};\n\nexport default useSpring;\n"
  },
  {
    "path": "src/useStartTyping.ts",
    "content": "import useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect';\nimport { off, on } from './misc/util';\n\nconst isFocusedElementEditable = () => {\n  const { activeElement, body } = document;\n\n  if (!activeElement) {\n    return false;\n  }\n\n  // If not element has focus, we assume it is not editable, too.\n  if (activeElement === body) {\n    return false;\n  }\n\n  // Assume <input> and <textarea> elements are editable.\n  switch (activeElement.tagName) {\n    case 'INPUT':\n    case 'TEXTAREA':\n      return true;\n  }\n\n  // Check if any other focused element id editable.\n  return activeElement.hasAttribute('contenteditable');\n};\n\nconst isTypedCharGood = ({ keyCode, metaKey, ctrlKey, altKey }: KeyboardEvent) => {\n  if (metaKey || ctrlKey || altKey) {\n    return false;\n  }\n  // 0...9\n  if (keyCode >= 48 && keyCode <= 57) {\n    return true;\n  }\n  // a...z\n  if (keyCode >= 65 && keyCode <= 90) {\n    return true;\n  }\n  // All other keys.\n  return false;\n};\n\nconst useStartTyping = (onStartTyping: (event: KeyboardEvent) => void) => {\n  useIsomorphicLayoutEffect(() => {\n    const keydown = (event) => {\n      !isFocusedElementEditable() && isTypedCharGood(event) && onStartTyping(event);\n    };\n\n    on(document, 'keydown', keydown);\n    return () => {\n      off(document, 'keydown', keydown);\n    };\n  }, []);\n};\n\nexport default useStartTyping;\n"
  },
  {
    "path": "src/useStateList.ts",
    "content": "import { useMemo, useRef } from 'react';\nimport useMountedState from './useMountedState';\nimport useUpdate from './useUpdate';\nimport useUpdateEffect from './useUpdateEffect';\n\nexport interface UseStateListReturn<T> {\n  state: T;\n  currentIndex: number;\n  setStateAt: (newIndex: number) => void;\n  setState: (state: T) => void;\n  next: () => void;\n  prev: () => void;\n  isFirst: boolean;\n  isLast: boolean;\n}\n\nexport default function useStateList<T>(stateSet: T[] = []): UseStateListReturn<T> {\n  const isMounted = useMountedState();\n  const update = useUpdate();\n  const index = useRef(0);\n\n  // If new state list is shorter that before - switch to the last element\n  useUpdateEffect(() => {\n    if (stateSet.length <= index.current) {\n      index.current = stateSet.length - 1;\n      update();\n    }\n  }, [stateSet.length]);\n\n  const actions = useMemo(\n    () => ({\n      next: () => actions.setStateAt(index.current + 1),\n      prev: () => actions.setStateAt(index.current - 1),\n      setStateAt: (newIndex: number) => {\n        // do nothing on unmounted component\n        if (!isMounted()) return;\n\n        // do nothing on empty states list\n        if (!stateSet.length) return;\n\n        // in case new index is equal current - do nothing\n        if (newIndex === index.current) return;\n\n        // it gives the ability to travel through the left and right borders.\n        // 4ex: if list contains 5 elements, attempt to set index 9 will bring use to 5th element\n        // in case of negative index it will start counting from the right, so -17 will bring us to 4th element\n        index.current =\n          newIndex >= 0\n            ? newIndex % stateSet.length\n            : stateSet.length + (newIndex % stateSet.length);\n        update();\n      },\n      setState: (state: T) => {\n        // do nothing on unmounted component\n        if (!isMounted()) return;\n\n        const newIndex = stateSet.length ? stateSet.indexOf(state) : -1;\n\n        if (newIndex === -1) {\n          throw new Error(`State '${state}' is not a valid state (does not exist in state list)`);\n        }\n\n        index.current = newIndex;\n        update();\n      },\n    }),\n    [stateSet]\n  );\n\n  return {\n    state: stateSet[index.current],\n    currentIndex: index.current,\n    isFirst: index.current === 0,\n    isLast: index.current === stateSet.length - 1,\n    ...actions,\n  };\n}\n"
  },
  {
    "path": "src/useStateValidator.ts",
    "content": "import { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react';\n\nexport type ValidityState = [boolean | undefined, ...any[]] | [undefined];\n\nexport interface StateValidator<V, S> {\n  (state: S): V;\n\n  (state: S, dispatch: Dispatch<SetStateAction<V>>): void;\n}\n\nexport type UseStateValidatorReturn<V> = [V, () => void];\n\nexport default function useStateValidator<V extends ValidityState, S>(\n  state: S,\n  validator: StateValidator<V, S>,\n  initialState: V = [undefined] as V\n): UseStateValidatorReturn<V> {\n  const validatorInner = useRef(validator);\n  const stateInner = useRef(state);\n\n  validatorInner.current = validator;\n  stateInner.current = state;\n\n  const [validity, setValidity] = useState(initialState as V);\n\n  const validate = useCallback(() => {\n    if (validatorInner.current.length >= 2) {\n      validatorInner.current(stateInner.current, setValidity as Dispatch<SetStateAction<V>>);\n    } else {\n      setValidity(validatorInner.current(stateInner.current));\n    }\n  }, [setValidity]);\n\n  useEffect(() => {\n    validate();\n  }, [state]);\n\n  return [validity, validate];\n}\n"
  },
  {
    "path": "src/useStateWithHistory.ts",
    "content": "import { Dispatch, useCallback, useMemo, useRef, useState } from 'react';\nimport { useFirstMountState } from './useFirstMountState';\nimport { IHookStateInitAction, IHookStateSetAction, resolveHookState } from './misc/hookState';\n\ninterface HistoryState<S> {\n  history: S[];\n  position: number;\n  capacity: number;\n  back: (amount?: number) => void;\n  forward: (amount?: number) => void;\n  go: (position: number) => void;\n}\n\nexport type UseStateHistoryReturn<S> = [S, Dispatch<IHookStateSetAction<S>>, HistoryState<S>];\n\nexport function useStateWithHistory<S, I extends S>(\n  initialState: IHookStateInitAction<S>,\n  capacity?: number,\n  initialHistory?: I[]\n): UseStateHistoryReturn<S>;\nexport function useStateWithHistory<S = undefined>(): UseStateHistoryReturn<S | undefined>;\n\nexport function useStateWithHistory<S, I extends S>(\n  initialState?: IHookStateInitAction<S>,\n  capacity: number = 10,\n  initialHistory?: I[]\n): UseStateHistoryReturn<S> {\n  if (capacity < 1) {\n    throw new Error(`Capacity has to be greater than 1, got '${capacity}'`);\n  }\n\n  const isFirstMount = useFirstMountState();\n  const [state, innerSetState] = useState<S>(initialState as S);\n  const history = useRef<S[]>((initialHistory ?? []) as S[]);\n  const historyPosition = useRef(0);\n\n  // do the states manipulation only on first mount, no sense to load re-renders with useless calculations\n  if (isFirstMount) {\n    if (history.current.length) {\n      // if last element of history !== initial - push initial to history\n      if (history.current[history.current.length - 1] !== initialState) {\n        history.current.push(initialState as I);\n      }\n\n      // if initial history bigger that capacity - crop the first elements out\n      if (history.current.length > capacity) {\n        history.current = history.current.slice(history.current.length - capacity);\n      }\n    } else {\n      // initiate the history with initial state\n      history.current.push(initialState as I);\n    }\n\n    historyPosition.current = history.current.length && history.current.length - 1;\n  }\n\n  const setState = useCallback(\n    (newState: IHookStateSetAction<S>): void => {\n      innerSetState((currentState) => {\n        newState = resolveHookState(newState, currentState);\n\n        // is state has changed\n        if (newState !== currentState) {\n          // if current position is not the last - pop element to the right\n          if (historyPosition.current < history.current.length - 1) {\n            history.current = history.current.slice(0, historyPosition.current + 1);\n          }\n\n          historyPosition.current = history.current.push(newState as I) - 1;\n\n          // if capacity is reached - shift first elements\n          if (history.current.length > capacity) {\n            history.current = history.current.slice(history.current.length - capacity);\n          }\n        }\n\n        return newState;\n      });\n    },\n    [state, capacity]\n  ) as Dispatch<IHookStateSetAction<S>>;\n\n  const historyState = useMemo(\n    () => ({\n      history: history.current,\n      position: historyPosition.current,\n      capacity,\n      back: (amount: number = 1) => {\n        // don't do anything if we already at the left border\n        if (!historyPosition.current) {\n          return;\n        }\n\n        innerSetState(() => {\n          historyPosition.current -= Math.min(amount, historyPosition.current);\n\n          return history.current[historyPosition.current];\n        });\n      },\n      forward: (amount: number = 1) => {\n        // don't do anything if we already at the right border\n        if (historyPosition.current === history.current.length - 1) {\n          return;\n        }\n\n        innerSetState(() => {\n          historyPosition.current = Math.min(\n            historyPosition.current + amount,\n            history.current.length - 1\n          );\n\n          return history.current[historyPosition.current];\n        });\n      },\n      go: (position: number) => {\n        if (position === historyPosition.current) {\n          return;\n        }\n\n        innerSetState(() => {\n          historyPosition.current =\n            position < 0\n              ? Math.max(history.current.length + position, 0)\n              : Math.min(history.current.length - 1, position);\n\n          return history.current[historyPosition.current];\n        });\n      },\n    }),\n    [state]\n  );\n\n  return [state, setState, historyState];\n}\n"
  },
  {
    "path": "src/useThrottle.ts",
    "content": "import { useEffect, useRef, useState } from 'react';\nimport useUnmount from './useUnmount';\n\nconst useThrottle = <T>(value: T, ms: number = 200) => {\n  const [state, setState] = useState<T>(value);\n  const timeout = useRef<ReturnType<typeof setTimeout>>();\n  const nextValue = useRef(null) as any;\n  const hasNextValue = useRef(0) as any;\n\n  useEffect(() => {\n    if (!timeout.current) {\n      setState(value);\n      const timeoutCallback = () => {\n        if (hasNextValue.current) {\n          hasNextValue.current = false;\n          setState(nextValue.current);\n          timeout.current = setTimeout(timeoutCallback, ms);\n        } else {\n          timeout.current = undefined;\n        }\n      };\n      timeout.current = setTimeout(timeoutCallback, ms);\n    } else {\n      nextValue.current = value;\n      hasNextValue.current = true;\n    }\n  }, [value]);\n\n  useUnmount(() => {\n    timeout.current && clearTimeout(timeout.current);\n  });\n\n  return state;\n};\n\nexport default useThrottle;\n"
  },
  {
    "path": "src/useThrottleFn.ts",
    "content": "import { useEffect, useRef, useState } from 'react';\nimport useUnmount from './useUnmount';\n\nconst useThrottleFn = <T, U extends any[]>(fn: (...args: U) => T, ms: number = 200, args: U) => {\n  const [state, setState] = useState<T | null>(null);\n  const timeout = useRef<ReturnType<typeof setTimeout>>();\n  const nextArgs = useRef<U>();\n\n  useEffect(() => {\n    if (!timeout.current) {\n      setState(fn(...args));\n      const timeoutCallback = () => {\n        if (nextArgs.current) {\n          setState(fn(...nextArgs.current));\n          nextArgs.current = undefined;\n          timeout.current = setTimeout(timeoutCallback, ms);\n        } else {\n          timeout.current = undefined;\n        }\n      };\n      timeout.current = setTimeout(timeoutCallback, ms);\n    } else {\n      nextArgs.current = args;\n    }\n  }, args);\n\n  useUnmount(() => {\n    timeout.current && clearTimeout(timeout.current);\n  });\n\n  return state;\n};\n\nexport default useThrottleFn;\n"
  },
  {
    "path": "src/useTimeout.ts",
    "content": "import useTimeoutFn from './useTimeoutFn';\nimport useUpdate from './useUpdate';\n\nexport type UseTimeoutReturn = [() => boolean | null, () => void, () => void];\n\nexport default function useTimeout(ms: number = 0): UseTimeoutReturn {\n  const update = useUpdate();\n\n  return useTimeoutFn(update, ms);\n}\n"
  },
  {
    "path": "src/useTimeoutFn.ts",
    "content": "import { useCallback, useEffect, useRef } from 'react';\n\nexport type UseTimeoutFnReturn = [() => boolean | null, () => void, () => void];\n\nexport default function useTimeoutFn(fn: Function, ms: number = 0): UseTimeoutFnReturn {\n  const ready = useRef<boolean | null>(false);\n  const timeout = useRef<ReturnType<typeof setTimeout>>();\n  const callback = useRef(fn);\n\n  const isReady = useCallback(() => ready.current, []);\n\n  const set = useCallback(() => {\n    ready.current = false;\n    timeout.current && clearTimeout(timeout.current);\n\n    timeout.current = setTimeout(() => {\n      ready.current = true;\n      callback.current();\n    }, ms);\n  }, [ms]);\n\n  const clear = useCallback(() => {\n    ready.current = null;\n    timeout.current && clearTimeout(timeout.current);\n  }, []);\n\n  // update ref when function changes\n  useEffect(() => {\n    callback.current = fn;\n  }, [fn]);\n\n  // set on mount, clear on unmount\n  useEffect(() => {\n    set();\n\n    return clear;\n  }, [ms]);\n\n  return [isReady, clear, set];\n}\n"
  },
  {
    "path": "src/useTitle.ts",
    "content": "import { useEffect, useRef } from 'react';\n\nexport interface UseTitleOptions {\n  restoreOnUnmount?: boolean;\n}\n\nconst DEFAULT_USE_TITLE_OPTIONS: UseTitleOptions = {\n  restoreOnUnmount: false,\n};\n\nfunction useTitle(title: string, options: UseTitleOptions = DEFAULT_USE_TITLE_OPTIONS) {\n  const prevTitleRef = useRef(document.title);\n\n  if (document.title !== title) document.title = title;\n\n  useEffect(() => {\n    if (options && options.restoreOnUnmount) {\n      return () => {\n        document.title = prevTitleRef.current;\n      };\n    } else {\n      return;\n    }\n  }, []);\n}\n\nexport default typeof document !== 'undefined' ? useTitle : (_title: string) => {};\n"
  },
  {
    "path": "src/useToggle.ts",
    "content": "import { Reducer, useReducer } from 'react';\n\nconst toggleReducer = (state: boolean, nextValue?: any) =>\n  typeof nextValue === 'boolean' ? nextValue : !state;\n\nconst useToggle = (initialValue: boolean): [boolean, (nextValue?: any) => void] => {\n  return useReducer<Reducer<boolean, any>>(toggleReducer, initialValue);\n};\n\nexport default useToggle;\n"
  },
  {
    "path": "src/useTween.ts",
    "content": "import { easing } from 'ts-easing';\nimport useRaf from './useRaf';\n\nexport type Easing = (t: number) => number;\n\nconst useTween = (easingName: string = 'inCirc', ms: number = 200, delay: number = 0): number => {\n  const fn: Easing = easing[easingName];\n  const t = useRaf(ms, delay);\n\n  if (process.env.NODE_ENV !== 'production') {\n    if (typeof fn !== 'function') {\n      console.error(\n        'useTween() expected \"easingName\" property to be a valid easing function name, like:' +\n          '\"' +\n          Object.keys(easing).join('\", \"') +\n          '\".'\n      );\n      console.trace();\n      return 0;\n    }\n  }\n\n  return fn(t);\n};\n\nexport default useTween;\n"
  },
  {
    "path": "src/useUnmount.ts",
    "content": "import { useRef } from 'react';\nimport useEffectOnce from './useEffectOnce';\n\nconst useUnmount = (fn: () => any): void => {\n  const fnRef = useRef(fn);\n\n  // update the ref each render so if it change the newest callback will be invoked\n  fnRef.current = fn;\n\n  useEffectOnce(() => () => fnRef.current());\n};\n\nexport default useUnmount;\n"
  },
  {
    "path": "src/useUnmountPromise.ts",
    "content": "import { useMemo, useRef } from 'react';\nimport useEffectOnce from './useEffectOnce';\n\nexport type Race = <P extends Promise<any>, E = any>(promise: P, onError?: (error: E) => void) => P;\n\nconst useUnmountPromise = (): Race => {\n  const refUnmounted = useRef(false);\n  useEffectOnce(() => () => {\n    refUnmounted.current = true;\n  });\n\n  const wrapper = useMemo(() => {\n    const race = <P extends Promise<any>, E>(promise: P, onError?: (error: E) => void) => {\n      const newPromise: P = new Promise((resolve, reject) => {\n        promise.then(\n          (result) => {\n            if (!refUnmounted.current) resolve(result);\n          },\n          (error) => {\n            if (!refUnmounted.current) reject(error);\n            else if (onError) onError(error);\n            else console.error('useUnmountPromise', error);\n          }\n        );\n      }) as P;\n      return newPromise;\n    };\n    return race;\n  }, []);\n\n  return wrapper;\n};\n\nexport default useUnmountPromise;\n"
  },
  {
    "path": "src/useUpdate.ts",
    "content": "import { useReducer } from 'react';\n\nconst updateReducer = (num: number): number => (num + 1) % 1_000_000;\n\nexport default function useUpdate(): () => void {\n  const [, update] = useReducer(updateReducer, 0);\n\n  return update;\n}\n"
  },
  {
    "path": "src/useUpdateEffect.ts",
    "content": "import { useEffect } from 'react';\nimport { useFirstMountState } from './useFirstMountState';\n\nconst useUpdateEffect: typeof useEffect = (effect, deps) => {\n  const isFirstMount = useFirstMountState();\n\n  useEffect(() => {\n    if (!isFirstMount) {\n      return effect();\n    }\n  }, deps);\n};\n\nexport default useUpdateEffect;\n"
  },
  {
    "path": "src/useUpsert.ts",
    "content": "import useList, { ListActions } from './useList';\nimport { IHookStateInitAction } from './misc/hookState';\n\nexport interface UpsertListActions<T> extends Omit<ListActions<T>, 'upsert'> {\n  upsert: (newItem: T) => void;\n}\n\n/**\n * @deprecated Use `useList` hook's upsert action instead\n */\nexport default function useUpsert<T>(\n  predicate: (a: T, b: T) => boolean,\n  initialList: IHookStateInitAction<T[]> = []\n): [T[], UpsertListActions<T>] {\n  const [list, listActions] = useList(initialList);\n\n  return [\n    list,\n    {\n      ...listActions,\n      upsert: (newItem: T) => {\n        listActions.upsert(predicate, newItem);\n      },\n    } as UpsertListActions<T>,\n  ];\n}\n"
  },
  {
    "path": "src/useVibrate.ts",
    "content": "import { useEffect } from 'react';\nimport { isNavigator, noop } from './misc/util';\n\nexport type VibrationPattern = number | number[];\n\nconst isVibrationApiSupported = isNavigator && 'vibrate' in navigator;\n\nfunction useVibrate(\n  enabled: boolean = true,\n  pattern: VibrationPattern = [1000, 1000],\n  loop: boolean = true\n): void {\n  useEffect(() => {\n    let interval;\n\n    if (enabled) {\n      navigator.vibrate(pattern);\n\n      if (loop) {\n        const duration =\n          pattern instanceof Array ? pattern.reduce((a, b) => a + b) : (pattern as number);\n\n        interval = setInterval(() => {\n          navigator.vibrate(pattern);\n        }, duration);\n      }\n    }\n\n    return () => {\n      if (enabled) {\n        navigator.vibrate(0);\n\n        if (loop) {\n          clearInterval(interval);\n        }\n      }\n    };\n  }, [enabled]);\n}\n\nexport default isVibrationApiSupported ? useVibrate : noop;\n"
  },
  {
    "path": "src/useVideo.ts",
    "content": "import createHTMLMediaHook from './factory/createHTMLMediaHook';\n\nconst useVideo = createHTMLMediaHook<HTMLVideoElement>('video');\n\nexport default useVideo;\n"
  },
  {
    "path": "src/useWait.ts",
    "content": ""
  },
  {
    "path": "src/useWindowScroll.ts",
    "content": "import { useEffect } from 'react';\n\nimport { isBrowser, off, on } from './misc/util';\nimport useRafState from './useRafState';\n\nexport interface State {\n  x: number;\n  y: number;\n}\n\nconst useWindowScroll = (): State => {\n  const [state, setState] = useRafState<State>(() => ({\n    x: isBrowser ? window.pageXOffset : 0,\n    y: isBrowser ? window.pageYOffset : 0,\n  }));\n\n  useEffect(() => {\n    const handler = () => {\n      setState((state) => {\n        const { pageXOffset, pageYOffset } = window;\n        //Check state for change, return same state if no change happened to prevent rerender\n        //(see useState/setState documentation). useState/setState is used internally in useRafState/setState.\n        return state.x !== pageXOffset || state.y !== pageYOffset\n          ? {\n              x: pageXOffset,\n              y: pageYOffset,\n            }\n          : state;\n      });\n    };\n\n    //We have to update window scroll at mount, before subscription.\n    //Window scroll may be changed between render and effect handler.\n    handler();\n\n    on(window, 'scroll', handler, {\n      capture: false,\n      passive: true,\n    });\n\n    return () => {\n      off(window, 'scroll', handler);\n    };\n  }, []);\n\n  return state;\n};\n\nexport default useWindowScroll;\n"
  },
  {
    "path": "src/useWindowSize.ts",
    "content": "import { useEffect } from 'react';\n\nimport useRafState from './useRafState';\nimport { isBrowser, off, on } from './misc/util';\n\n// Define the type for options that can be passed to the hook\ninterface Options {\n  initialWidth?: number; // Initial width of the window (Default value is Infinity)\n  initialHeight?: number; // Initial height of the window (Default value is Infinity)\n  onChange?: (width: number, height: number) => void; // Callback function to execute on window resize (optional)\n}\n\nconst useWindowSize = ({\n  initialWidth = Infinity,\n  initialHeight = Infinity,\n  onChange,\n}: Options = {}) => {\n  // Use the useRafState hook to maintain the current window size (width and height)\n  const [state, setState] = useRafState<{ width: number; height: number }>({\n    width: isBrowser ? window.innerWidth : initialWidth,\n    height: isBrowser ? window.innerHeight : initialHeight,\n  });\n\n  useEffect((): (() => void) | void => {\n    // Only run the effect on the browser (to avoid issues with SSR)\n    if (isBrowser) {\n      const handler = () => {\n        const width = window.innerWidth;\n        const height = window.innerHeight;\n\n        // Update the state with the new window size\n        setState({\n          width,\n          height,\n        });\n\n        // If an onChange callback is provided, call it with the new dimensions\n        if (onChange) onChange(width, height);\n      };\n\n      // Add event listener for the resize event\n      on(window, 'resize', handler);\n\n      // Cleanup function to remove the event listener when the component is unmounted (it's for performance optimization)\n      return () => {\n        off(window, 'resize', handler);\n      };\n    }\n  }, []);\n\n  // Return the current window size (width and height)\n  return state;\n};\n\nexport default useWindowSize;\n"
  },
  {
    "path": "stories/comps/UseKey.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport UseKey from '../../src/component/UseKey';\n\nstoriesOf('Components/<UseKey>', module).add('Demo', () => (\n  <div>\n    Press \"q\" key!\n    <UseKey filter=\"q\" fn={() => alert('Q pressed!')} />\n  </div>\n));\n"
  },
  {
    "path": "stories/createBreakpoint.story.tsx",
    "content": "import { withKnobs } from '@storybook/addon-knobs';\nimport { storiesOf } from '@storybook/react';\nimport React from 'react';\nimport { createBreakpoint } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst useBreakpointA = createBreakpoint();\nconst useBreakpointB = createBreakpoint({ mobileM: 350, laptop: 1024, tablet: 768 });\n\nconst Demo = () => {\n  const breakpointA = useBreakpointA();\n  const breakpointB = useBreakpointB();\n  return (\n    <div>\n      <p>{'try resize your window'}</p>\n      <p>{'createBreakpoint() #default : { laptopL: 1440, laptop: 1024, tablet: 768 }'}</p>\n      <p>{breakpointA}</p>\n      <p>{'createBreakpoint({ mobileM: 350, laptop: 1024, tablet: 768 })'}</p>\n      <p>{breakpointB}</p>\n    </div>\n  );\n};\n\nstoriesOf('sensors/createBreakpoint', module)\n  .addDecorator(withKnobs)\n  .add('Docs', () => <ShowDocs md={require('../docs/createBreakpoint.md')} />)\n  .add('Demo', () => {\n    return <Demo />;\n  });\n"
  },
  {
    "path": "stories/createGlobalState.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport React, { FC } from 'react';\nimport { createGlobalState } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst useGlobalValue = createGlobalState<number>(0);\n\nconst CompA: FC = () => {\n  const [value, setValue] = useGlobalValue();\n\n  return <button onClick={() => setValue(value + 1)}>+</button>;\n};\n\nconst CompB: FC = () => {\n  const [value, setValue] = useGlobalValue();\n\n  return <button onClick={() => setValue(value - 1)}>-</button>;\n};\n\nconst Demo: FC = () => {\n  const [value] = useGlobalValue();\n  return (\n    <div>\n      <p>{value}</p>\n      <CompA />\n      <CompB />\n    </div>\n  );\n};\n\nstoriesOf('State/createGlobalState', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/createGlobalState.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/createMemo.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { createMemo } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst fibonacci = (n) => {\n  if (n === 0) {\n    return 0;\n  }\n  if (n === 1) {\n    return 1;\n  }\n  return fibonacci(n - 1) + fibonacci(n - 2);\n};\n\nconst useMemoFibonacci = createMemo(fibonacci);\n\nconst Demo = () => {\n  const result = useMemoFibonacci(10);\n\n  return <div>fib(10) = {result}</div>;\n};\n\nstoriesOf('State/createMemo', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/createMemo.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/createReducer.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport logger from 'redux-logger';\nimport thunk from 'redux-thunk';\n\nimport { createReducer } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst useThunkReducer = createReducer(thunk, logger);\n\n// React useReducer lazy initialization example: https://reactjs.org/docs/hooks-reference.html#lazy-initialization\nfunction init(initialCount) {\n  return { count: initialCount };\n}\n\nfunction reducer(state, action) {\n  switch (action.type) {\n    case 'increment':\n      return { count: state.count + 1 };\n    case 'decrement':\n      return { count: state.count - 1 };\n    case 'reset':\n      return init(action.payload);\n    default:\n      throw new Error();\n  }\n}\n\nconst Demo = ({ initialCount = 1 }) => {\n  // Action creator to increment count, wait a second and then reset\n  const addAndReset = React.useCallback(() => {\n    return (dispatch2) => {\n      dispatch2({ type: 'increment' });\n\n      setTimeout(() => {\n        dispatch2({ type: 'reset', payload: initialCount });\n      }, 1000);\n    };\n  }, [initialCount]);\n\n  const [state, dispatch] = useThunkReducer(reducer, initialCount, init);\n\n  return (\n    <div>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      <button onClick={() => dispatch(addAndReset())}>Add and reset</button>\n      <button onClick={() => dispatch({ type: 'reset', payload: initialCount })}>Reset</button>\n      <button onClick={() => dispatch({ type: 'increment' })}>+</button>\n      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>\n      <p>Open your developer console to see actions logged by middleware</p>\n    </div>\n  );\n};\n\nstoriesOf('State/createReducer', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/createReducer.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/createReducerContext.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\n\nimport { createReducerContext } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\ntype Action = 'increment' | 'decrement';\n\nconst reducer = (state: number, action: Action) => {\n  switch (action) {\n    case 'increment':\n      return state + 1;\n    case 'decrement':\n      return state - 1;\n    default:\n      throw new Error();\n  }\n};\n\nconst [useSharedCounter, SharedCounterProvider] = createReducerContext(reducer, 0);\n\nconst ComponentA = () => {\n  const [count, dispatch] = useSharedCounter();\n  return (\n    <p>\n      Component A &nbsp;\n      <button type=\"button\" onClick={() => dispatch('decrement')}>\n        -\n      </button>\n      &nbsp;{count}&nbsp;\n      <button type=\"button\" onClick={() => dispatch('increment')}>\n        +\n      </button>\n    </p>\n  );\n};\n\nconst ComponentB = () => {\n  const [count, dispatch] = useSharedCounter();\n  return (\n    <p>\n      Component B &nbsp;\n      <button type=\"button\" onClick={() => dispatch('decrement')}>\n        -\n      </button>\n      &nbsp;{count}&nbsp;\n      <button type=\"button\" onClick={() => dispatch('increment')}>\n        +\n      </button>\n    </p>\n  );\n};\n\nconst Demo = () => {\n  return (\n    <SharedCounterProvider>\n      <p>Those two counters share the same value.</p>\n      <ComponentA />\n      <ComponentB />\n    </SharedCounterProvider>\n  );\n};\n\nstoriesOf('State/createReducerContext', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/createReducerContext.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/createStateContext.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\n\nimport { createStateContext } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst [useSharedText, SharedTextProvider] = createStateContext('');\n\nconst ComponentA = () => {\n  const [text, setText] = useSharedText();\n  return (\n    <p>\n      Component A:\n      <br />\n      <input type=\"text\" value={text} onInput={(ev) => setText(ev.currentTarget.value)} />\n    </p>\n  );\n};\n\nconst ComponentB = () => {\n  const [text, setText] = useSharedText();\n  return (\n    <p>\n      Component B:\n      <br />\n      <input type=\"text\" value={text} onInput={(ev) => setText(ev.currentTarget.value)} />\n    </p>\n  );\n};\n\nconst Demo = () => {\n  return (\n    <SharedTextProvider>\n      <p>Those two fields share the same value.</p>\n      <ComponentA />\n      <ComponentB />\n    </SharedTextProvider>\n  );\n};\n\nstoriesOf('State/createStateContext', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/createStateContext.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useAsync.story.tsx",
    "content": "import { number, withKnobs } from '@storybook/addon-knobs';\nimport { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useAsync } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = ({ delay }) => {\n  const state = useAsync<string>(\n    () =>\n      new Promise<string>((resolve, reject) => {\n        setTimeout(() => {\n          if (Math.random() > 0.5) {\n            resolve('✌️');\n          } else {\n            reject(new Error('A pseudo random error occurred'));\n          }\n        }, delay);\n      }),\n    [delay]\n  );\n\n  return (\n    <div>\n      {state.loading ? (\n        <p>Loading...</p>\n      ) : state.error ? (\n        <p>Error: {state.error.message}</p>\n      ) : (\n        <p>Value: {state.value}</p>\n      )}\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useAsync', module)\n  .addDecorator(withKnobs)\n  .add('Docs', () => <ShowDocs md={require('../docs/useAsync.md')} />)\n  .add('Demo', () => {\n    const delay = number('delay', 1000, { range: true, min: 100, max: 5000, step: 100 });\n    return <Demo delay={delay} />;\n  });\n"
  },
  {
    "path": "stories/useAsyncFn.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useAsyncFn } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [state, callback] = useAsyncFn<string>(\n    () =>\n      new Promise<string>((resolve, reject) => {\n        setTimeout(() => {\n          if (Math.random() > 0.5) {\n            resolve('✌️');\n          } else {\n            reject(new Error('A pseudo random error occurred'));\n          }\n        }, 1000);\n      })\n  );\n\n  return (\n    <div>\n      {state.loading ? (\n        <p>Loading...</p>\n      ) : state.error ? (\n        <p>Error: {state.error.message}</p>\n      ) : (\n        <p>Value: {state.value}</p>\n      )}\n      <button onClick={() => callback()}>Start</button>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useAsyncFn', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useAsyncFn.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useAsyncRetry.story.tsx",
    "content": "import { number, withKnobs } from '@storybook/addon-knobs';\nimport { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useAsyncRetry } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = ({ delay }) => {\n  const state = useAsyncRetry<string>(\n    () =>\n      new Promise<string>((resolve, reject) => {\n        setTimeout(() => {\n          if (Math.random() > 0.5) {\n            resolve('✌️');\n          } else {\n            reject(new Error('A pseudo random error occurred'));\n          }\n        }, delay);\n      }),\n    [delay]\n  );\n\n  return (\n    <div>\n      {state.loading ? (\n        <p>Loading...</p>\n      ) : state.error ? (\n        <p>Error: {state.error.message}</p>\n      ) : (\n        <p>Value: {state.value}</p>\n      )}\n      <button onClick={() => state.retry()}>Retry</button>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useAsyncRetry', module)\n  .addDecorator(withKnobs)\n  .add('Docs', () => <ShowDocs md={require('../docs/useAsyncRetry.md')} />)\n  .add('Demo', () => {\n    const delay = number('delay', 1000, { range: true, min: 100, max: 5000, step: 100 });\n    return <Demo delay={delay} />;\n  });\n"
  },
  {
    "path": "stories/useAudio.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useAudio } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [audio, state, controls, ref] = useAudio({\n    src: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3',\n    autoPlay: true,\n  });\n\n  return (\n    <div>\n      {audio}\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      <button onClick={controls.pause}>Pause</button>\n      <button onClick={controls.play}>Play</button>\n      <br />\n      <button onClick={controls.mute}>Mute</button>\n      <button onClick={controls.unmute}>Un-mute</button>\n      <br />\n      <button onClick={() => controls.volume(0.1)}>Volume: 10%</button>\n      <button onClick={() => controls.volume(0.5)}>Volume: 50%</button>\n      <button onClick={() => controls.volume(1)}>Volume: 100%</button>\n      <br />\n      <button onClick={() => controls.seek(state.time - 5)}>-5 sec</button>\n      <button onClick={() => controls.seek(state.time + 5)}>+5 sec</button>\n    </div>\n  );\n};\n\nstoriesOf('UI/useAudio', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useAudio.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useBattery.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useBattery } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const batteryState = useBattery();\n\n  if (!batteryState.isSupported) {\n    return (\n      <div>\n        <strong>Battery sensor</strong>: <span>not supported</span>\n      </div>\n    );\n  }\n\n  if (!batteryState.fetched) {\n    return (\n      <div>\n        <strong>Battery sensor</strong>: <span>supported</span> <br />\n        <strong>Battery state</strong>: <span>fetching</span>\n      </div>\n    );\n  }\n\n  return (\n    <div>\n      <strong>Battery sensor</strong>:&nbsp;&nbsp; <span>supported</span> <br />\n      <strong>Battery state</strong>: <span>fetched</span> <br />\n      <strong>Charge level</strong>:&nbsp;&nbsp;{' '}\n      <span>{(batteryState.level * 100).toFixed(0)}%</span> <br />\n      <strong>Charging</strong>:&nbsp;&nbsp; <span>{batteryState.charging ? 'yes' : 'no'}</span>{' '}\n      <br />\n      <strong>Charging time</strong>:&nbsp;&nbsp;\n      <span>{batteryState.chargingTime ? batteryState.chargingTime : 'finished'}</span> <br />\n      <strong>Discharging time</strong>:&nbsp;&nbsp; <span>{batteryState.dischargingTime}</span>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useBattery', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useBattery.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useBeforeUnload.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport React, { useCallback } from 'react';\nimport { useBeforeUnload, useToggle } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst DemoBool = () => {\n  const [dirty, toggleDirty] = useToggle(false);\n  useBeforeUnload(dirty, 'You have unsaved changes, are you sure?');\n\n  return (\n    <div>\n      {dirty && <p>Try to reload or close tab</p>}\n      <button onClick={() => toggleDirty()}>{dirty ? 'Disable' : 'Enable'}</button>\n    </div>\n  );\n};\n\nconst DemoFunc = () => {\n  const [dirty, toggleDirty] = useToggle(false);\n  const dirtyFn = useCallback(() => {\n    return dirty;\n  }, [dirty]);\n  useBeforeUnload(dirtyFn, 'You have unsaved changes, are you sure?');\n\n  return (\n    <div>\n      {dirty && <p>Try to reload or close tab</p>}\n      <button onClick={() => toggleDirty()}>{dirty ? 'Disable' : 'Enable'}</button>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useBeforeUnload', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useBeforeUnload.md')} />)\n  .add('Demo (boolean)', () => <DemoBool />)\n  .add('Demo (function)', () => <DemoFunc />);\n"
  },
  {
    "path": "stories/useBoolean.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useBoolean } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [on, toggle] = useBoolean(true);\n\n  return (\n    <div>\n      <div>{on ? 'ON' : 'OFF'}</div>\n      <button onClick={() => toggle()}>Toggle</button>\n      <button onClick={() => toggle(true)}>set ON</button>\n      <button onClick={() => toggle(false)}>set OFF</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useBoolean', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useToggle.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useClickAway.story.tsx",
    "content": "import { action } from '@storybook/addon-actions';\nimport { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useRef } from 'react';\nimport { useClickAway } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const ref = useRef(null);\n  useClickAway<MouseEvent>(ref, action('outside clicked'));\n\n  return (\n    <div\n      ref={ref}\n      style={{\n        width: 200,\n        height: 200,\n        background: 'red',\n      }}\n    />\n  );\n};\n\nstoriesOf('UI/useClickAway', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useClickAway.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useCookie.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport React, { useState, useEffect } from 'react';\nimport { useCookie } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [value, updateCookie, deleteCookie] = useCookie('my-cookie');\n  const [counter, setCounter] = useState(1);\n\n  useEffect(() => {\n    deleteCookie();\n  }, []);\n\n  const updateCookieHandler = () => {\n    updateCookie(`my-awesome-cookie-${counter}`);\n    setCounter((c) => c + 1);\n  };\n\n  return (\n    <div>\n      <p>Value: {value}</p>\n      <button onClick={updateCookieHandler}>Update Cookie</button>\n      <br />\n      <button onClick={deleteCookie}>Delete Cookie</button>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useCookie', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useCookie.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useCopyToClipboard.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCopyToClipboard } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [text, setText] = React.useState('');\n  const [state, copyToClipboard] = useCopyToClipboard();\n\n  return (\n    <div>\n      <input value={text} onChange={(e) => setText(e.target.value)} />\n      <button type=\"button\" onClick={() => copyToClipboard(text)}>\n        copy text\n      </button>\n      {state.error ? (\n        <p>Unable to copy value: {state.error.message}</p>\n      ) : (\n        state.value && (\n          <>\n            <p>\n              Copied {state.value} {state.noUserInteraction ? 'without' : 'with'} user interaction\n            </p>\n            <input type=\"text\" placeholder=\"Paste it in here to check\" />\n          </>\n        )\n      )}\n    </div>\n  );\n};\n\nstoriesOf('Side-effects/useCopyToClipboard', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useCopyToClipboard.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useCounter.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCounter } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [initialValue, setInitialValue] = React.useState(5);\n  const [min, { inc: incMin, dec: decMin }] = useCounter(1);\n  const [max, { inc: incMax, dec: decMax }] = useCounter(10);\n  const [value, { inc, dec, set, reset }] = useCounter(initialValue, max, min);\n\n  return (\n    <div>\n      <div>\n        current: {value} [min: {min}; max: {max}]\n      </div>\n      <br />\n      Current value: <button onClick={() => inc()}>Increment</button>\n      <button onClick={() => dec()}>Decrement</button>\n      <button onClick={() => inc(5)}>Increment (+5)</button>\n      <button onClick={() => dec(5)}>Decrement (-5)</button>\n      <button onClick={() => set(100)}>Set 100</button>\n      <button onClick={() => reset()}>Reset</button>\n      <button onClick={() => reset(25)}>Reset (25)</button>\n      <br />\n      <br />\n      Min value:\n      <button onClick={() => incMin()}>Increment</button>\n      <button onClick={() => decMin()}>Decrement</button>\n      <br />\n      <br />\n      Max value:\n      <button onClick={() => incMax()}>Increment</button>\n      <button onClick={() => decMax()}>Decrement</button>\n      <br />\n      <br />\n      Initial value: {initialValue}\n      <button onClick={() => setInitialValue((v) => ++v)}>Increment</button>\n      <button onClick={() => setInitialValue((v) => --v)}>Decrement</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useCounter', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useCounter.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useCss.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCss } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const className = useCss({\n    color: 'red',\n    border: '1px solid red',\n    '&:hover': {\n      color: 'blue',\n    },\n  });\n\n  return <div className={className}>hello</div>;\n};\n\nstoriesOf('UI/useCss', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useCss.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useCustomCompareEffect.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCounter, useCustomCompareEffect } from '../src';\nimport ShowDocs from './util/ShowDocs';\nimport isDeepEqual from '../src/misc/isDeepEqual';\n\nconst Demo = () => {\n  const [countNormal, { inc: incNormal }] = useCounter(0);\n  const [countDeep, { inc: incDeep }] = useCounter(0);\n  const options = { max: 500 };\n\n  React.useEffect(() => {\n    if (countNormal < options.max) {\n      incNormal();\n    }\n  }, [options]);\n\n  useCustomCompareEffect(\n    () => {\n      if (countNormal < options.max) {\n        incDeep();\n      }\n    },\n    [options],\n    (prevDeps, nextDeps) => isDeepEqual(prevDeps, nextDeps)\n  );\n\n  return (\n    <div>\n      <p>useEffect: {countNormal}</p>\n      <p>useCustomCompareEffect: {countDeep}</p>\n    </div>\n  );\n};\n\nstoriesOf('Lifecycle/useCustomCompareEffect', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useCustomCompareEffect.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useDebounce.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useDebounce } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [state, setState] = React.useState('Typing stopped');\n  const [val, setVal] = React.useState('');\n  const [debouncedValue, setDebouncedValue] = React.useState('');\n\n  const [, cancel] = useDebounce(\n    () => {\n      setState('Typing stopped');\n      setDebouncedValue(val);\n    },\n    2000,\n    [val]\n  );\n\n  return (\n    <div>\n      <input\n        type=\"text\"\n        value={val}\n        placeholder=\"Debounced input\"\n        onChange={({ currentTarget }) => {\n          setState('Waiting for typing to stop...');\n          setVal(currentTarget.value);\n        }}\n      />\n      <div>{state}</div>\n      <div>\n        Debounced value: {debouncedValue}\n        <button onClick={cancel}>Cancel debounce</button>\n      </div>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useDebounce', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useDebounce.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useDeepCompareEffect.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCounter, useDeepCompareEffect } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [countNormal, { inc: incNormal }] = useCounter(0);\n  const [countDeep, { inc: incDeep }] = useCounter(0);\n  const options = { max: 500 };\n\n  React.useEffect(() => {\n    if (countNormal < options.max) {\n      incNormal();\n    }\n  }, [options]);\n\n  useDeepCompareEffect(() => {\n    if (countNormal < options.max) {\n      incDeep();\n    }\n  }, [options]);\n\n  return (\n    <div>\n      <p>useEffect: {countNormal}</p>\n      <p>useDeepCompareEffect: {countDeep}</p>\n    </div>\n  );\n};\n\nstoriesOf('Lifecycle/useDeepCompareEffect', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useDeepCompareEffect.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useDefault.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useDefault } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const initialUser = { name: 'Marshall' };\n  const defaultUser = { name: 'Mathers' };\n  const [user, setUser] = useDefault(defaultUser, initialUser);\n\n  return (\n    <div>\n      <div>User: {user.name}</div>\n      <input onChange={(e) => setUser({ name: e.target.value })} />\n      <button onClick={() => setUser(null)}>set to null</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useDefault', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useDefault.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useDrop.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useDrop } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const state = useDrop({\n    onFiles: (...args) => console.log('onFiles', ...args),\n    onUri: (...args) => console.log('onUri', ...args),\n    onText: (...args) => console.log('onText', ...args),\n  });\n\n  const style: React.CSSProperties = {\n    width: 300,\n    height: 200,\n    margin: '50px auto',\n    border: '1px dotted #000',\n    textAlign: 'center',\n    lineHeight: '200px',\n    ...(state.over\n      ? {\n          border: '1px dotted green',\n          outline: '3px solid yellow',\n          background: '#f8f8f8',\n        }\n      : {}),\n  };\n\n  return (\n    <div>\n      <div style={style}>Drop anywhere on page</div>\n      <div style={{ maxWidth: 300, margin: '0 auto' }}>\n        <ul style={{ margin: 0, padding: '10px 18px' }}>\n          <li>\n            See logs in <code>Actions</code> tab.\n          </li>\n          <li>Drag in and drop files.</li>\n          <li>\n            <code>Cmd + V</code> paste text here.\n          </li>\n          <li>Drag in images from other tabs.</li>\n          <li>Drag in link from navigation bar.</li>\n          <li>Below is state returned by the hook:</li>\n        </ul>\n        <pre>{JSON.stringify(state, null, 4)}</pre>\n      </div>\n    </div>\n  );\n};\n\nstoriesOf('UI/useDrop', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useDrop.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useDropArea.story.tsx",
    "content": "import { action } from '@storybook/addon-actions';\nimport { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useDropArea } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [bond, state] = useDropArea({\n    onFiles: action('onFiles'),\n    onUri: action('onUri'),\n    onText: action('onText'),\n  });\n\n  const style: React.CSSProperties = {\n    width: 300,\n    height: 200,\n    margin: '50px auto',\n    border: '1px solid #000',\n    textAlign: 'center',\n    lineHeight: '200px',\n    ...(state.over\n      ? {\n          border: '1px solid green',\n          outline: '3px solid yellow',\n          background: '#f8f8f8',\n        }\n      : {}),\n  };\n\n  return (\n    <div>\n      <div {...bond} style={style}>\n        Drop here\n      </div>\n      <div style={{ maxWidth: 300, margin: '0 auto' }}>\n        <ul style={{ margin: 0, padding: '10px 18px' }}>\n          <li>\n            See logs in <code>Actions</code> tab.\n          </li>\n          <li>Drag in and drop files.</li>\n          <li>\n            <code>Cmd + V</code> paste text here.\n          </li>\n          <li>Drag in images from other tabs.</li>\n          <li>Drag in link from navigation bar.</li>\n          <li>Below is state returned by the hook:</li>\n        </ul>\n        <pre>{JSON.stringify(state, null, 4)}</pre>\n      </div>\n    </div>\n  );\n};\n\nstoriesOf('UI/useDropArea', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useDrop.md')} />)\n  .add('Default', () => <Demo />);\n"
  },
  {
    "path": "stories/useEffectOnce.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useEffectOnce } from '../src';\nimport ConsoleStory from './util/ConsoleStory';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  useEffectOnce(() => {\n    console.log('Running effect once on mount');\n\n    return () => {\n      console.log('Running clean-up of effect on unmount');\n    };\n  });\n\n  return <ConsoleStory />;\n};\n\nstoriesOf('Lifecycle/useEffectOnce', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useEffectOnce.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useEnsuredForwardedRef.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport React, { forwardRef, useRef, useState, useEffect, MutableRefObject } from 'react';\nimport { useEnsuredForwardedRef } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nimport { boolean, withKnobs } from '@storybook/addon-knobs';\n\nconst INITIAL_SIZE = {\n  width: null,\n  height: null,\n};\n\nconst Demo = ({ activeForwardRef }) => {\n  const ref = useRef(null);\n\n  const [size, setSize] = useState(INITIAL_SIZE);\n\n  useEffect(() => {\n    handleClick();\n  }, [activeForwardRef]);\n\n  const handleClick = () => {\n    if (activeForwardRef) {\n      const { width, height } = ref.current.getBoundingClientRect();\n      setSize({\n        width,\n        height,\n      });\n    } else {\n      setSize(INITIAL_SIZE);\n    }\n  };\n\n  return (\n    <>\n      <button onClick={handleClick} disabled={!activeForwardRef}>\n        {activeForwardRef ? 'Update parent component' : 'forwardRef value is undefined'}\n      </button>\n      <div>Parent component using external ref: (textarea size)</div>\n      <pre>{JSON.stringify(size, null, 2)}</pre>\n      <Child ref={activeForwardRef ? ref : undefined} />\n    </>\n  );\n};\n\nconst Child = forwardRef(({}, ref: MutableRefObject<HTMLTextAreaElement>) => {\n  const ensuredForwardRef = useEnsuredForwardedRef(ref);\n\n  const [size, setSize] = useState(INITIAL_SIZE);\n\n  useEffect(() => {\n    handleMouseUp();\n  }, []);\n\n  const handleMouseUp = () => {\n    const { width, height } = ensuredForwardRef.current.getBoundingClientRect();\n    setSize({\n      width,\n      height,\n    });\n  };\n\n  return (\n    <>\n      <div>Child forwardRef component using forwardRef: (textarea size)</div>\n      <pre>{JSON.stringify(size, null, 2)}</pre>\n      <div>You can resize this textarea:</div>\n      <textarea ref={ensuredForwardRef} onMouseUp={handleMouseUp} />\n    </>\n  );\n});\n\nstoriesOf('Miscellaneous/useEnsuredForwardedRef', module)\n  .addDecorator(withKnobs)\n  .add('Docs', () => <ShowDocs md={require('../docs/useEnsuredForwardedRef.md')} />)\n  .add('Demo', () => {\n    const activeForwardRef = boolean('activeForwardRef', true);\n    return <Demo activeForwardRef={activeForwardRef} />;\n  });\n"
  },
  {
    "path": "stories/useError.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport React from 'react';\nimport { useError } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nclass ErrorBoundary extends React.Component<{}, { hasError: boolean }> {\n  constructor(props) {\n    super(props);\n    this.state = { hasError: false };\n  }\n\n  static getDerivedStateFromError(error) {\n    return { hasError: true };\n  }\n\n  render() {\n    if (this.state.hasError) {\n      return (\n        <div>\n          <h1>Something went wrong.</h1>\n          <button onClick={() => this.setState({ hasError: false })}>Retry</button>\n        </div>\n      );\n    }\n\n    return this.props.children;\n  }\n}\n\nconst Demo = () => {\n  const dispatchError = useError();\n\n  const clickHandler = () => {\n    dispatchError(new Error('Some error!'));\n  };\n\n  return <button onClick={clickHandler}>Click me to throw</button>;\n};\n\nstoriesOf('Side effects/useError', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useError.md')} />)\n  .add('Demo', () => (\n    <ErrorBoundary>\n      <Demo />\n    </ErrorBoundary>\n  ));\n"
  },
  {
    "path": "stories/useEvent.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useEvent, useList } from '../src';\nimport { CenterStory } from './util/CenterStory';\nimport ShowDocs from './util/ShowDocs';\n\nconst { useCallback } = React;\n\nconst Demo = () => {\n  const [list, { push, clear }] = useList();\n\n  const onKeyDown = useCallback(({ key }) => {\n    if (key === 'r') {\n      clear();\n    }\n    push(key);\n  }, []);\n\n  useEvent('keydown', onKeyDown);\n\n  return (\n    <CenterStory>\n      <p>\n        Press some keys on your keyboard, <code style={{ color: 'tomato' }}>r</code> key resets the\n        list\n      </p>\n      <pre>{JSON.stringify(list, null, 4)}</pre>\n    </CenterStory>\n  );\n};\n\nstoriesOf('Sensors/useEvent', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useEvent.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useFavicon.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useFavicon } from '../src';\nimport NewTabStory from './util/NewTabStory';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  useFavicon('https://cdn.sstatic.net/Sites/stackoverflow/img/favicon.ico');\n\n  return <NewTabStory>Favicon should be the Stack Overflow logo</NewTabStory>;\n};\n\nstoriesOf('Side effects/useFavicon', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useFavicon.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useFirstMountState.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useFirstMountState } from '../src/useFirstMountState';\nimport useUpdate from '../src/useUpdate';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const isFirstMount = useFirstMountState();\n  const update = useUpdate();\n\n  return (\n    <div>\n      <span>This component is just mounted: {isFirstMount ? 'YES' : 'NO'}</span>\n      <br />\n      <button onClick={update}>re-render</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useFirstMountState', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useFirstMountState.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useFullscreen.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useFullscreen, useToggle } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [show, toggle] = useToggle(false);\n  const ref = React.useRef(null);\n  const videoRef = React.useRef(null);\n  const isFullScreen = useFullscreen(ref, show, {\n    onClose: () => toggle(false),\n    video: videoRef,\n  });\n\n  const controls = (\n    <div style={{ background: 'white', padding: '20px' }}>\n      <div>{isFullScreen ? 'is full screen' : 'not full screen'}</div>\n      <button onClick={() => toggle()}>Toggle</button>\n      <button onClick={() => toggle(true)}>set ON</button>\n      <button onClick={() => toggle(false)}>set OFF</button>\n    </div>\n  );\n\n  return (\n    <div>\n      <div\n        ref={ref}\n        style={{\n          backgroundColor: isFullScreen ? 'black' : 'grey',\n          width: 400,\n          height: 300,\n          display: 'flex',\n          justifyContent: 'center',\n          alignItems: 'center',\n        }}>\n        <video\n          ref={videoRef}\n          style={{ width: '70%' }}\n          src=\"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4\"\n          autoPlay={true}\n        />\n        {isFullScreen && controls}\n      </div>\n\n      <br />\n      <br />\n\n      {!isFullScreen && controls}\n    </div>\n  );\n};\n\nstoriesOf('UI/useFullscreen', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useFullscreen.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useGeolocation.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useGeolocation } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const state = useGeolocation();\n\n  return <pre>{JSON.stringify(state, null, 2)}</pre>;\n};\n\nstoriesOf('Sensors/useGeolocation', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useGeolocation.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useGetSet.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useState } from 'react';\nimport { useGetSet } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [get, set] = useGetSet(0);\n  const onClick = () => {\n    setTimeout(() => {\n      set(get() + 1);\n    }, 1_000);\n  };\n\n  return <button onClick={onClick}>Clicked: {get()}</button>;\n};\n\nconst DemoWrong = () => {\n  const [cnt, set] = useState(0);\n  const onClick = () => {\n    setTimeout(() => {\n      set(cnt + 1);\n    }, 1_000);\n  };\n\n  return <button onClick={onClick}>Clicked: {cnt}</button>;\n};\n\nstoriesOf('State/useGetSet', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useGetSet.md')} />)\n  .add('Demo, 1s delay', () => <Demo />)\n  .add('DemoWrong, 1s delay', () => <DemoWrong />);\n"
  },
  {
    "path": "stories/useGetSetState.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useGetSetState } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [get, setState] = useGetSetState<{ cnt: number }>({ cnt: 0 });\n  const onClick = () => {\n    setTimeout(() => {\n      setState({ cnt: get().cnt + 1 });\n    }, 1_000);\n  };\n\n  return <button onClick={onClick}>Clicked: {get().cnt}</button>;\n};\n\nstoriesOf('State/useGetSetState', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useGetSetState.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useHarmonicIntervalFn.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useHarmonicIntervalFn, useInterval, useTimeoutFn } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Clock = ({\n  useInt,\n}: {\n  children?: React.ReactNode;\n  useInt: typeof useHarmonicIntervalFn;\n}) => {\n  const [count, setCount] = React.useState(0);\n  useInt(() => {\n    setCount((cnt) => cnt + 1);\n  }, 1000);\n\n  let m: number | string = Math.floor(count / 60);\n  let s: number | string = count % 60;\n\n  m = m < 10 ? '0' + m : String(m);\n  s = s < 10 ? '0' + s : String(s);\n\n  const style: React.CSSProperties = {\n    padding: '20px 5px',\n    border: '1px solid #fafafa',\n    float: 'left',\n    fontFamily: 'monospace',\n  };\n\n  return <div style={style}>{m + ':' + s}</div>;\n};\n\nconst Demo = ({ useInt }: { children?: React.ReactNode; useInt: typeof useHarmonicIntervalFn }) => {\n  const [showSecondClock, setShowSecondClock] = React.useState(false);\n  useTimeoutFn(() => {\n    setShowSecondClock(true);\n  }, 500);\n\n  const headingStyle: React.CSSProperties = {\n    fontFamily: 'sans',\n    fontSize: '20px',\n    padding: '0',\n    lineHeight: '1.5em',\n  };\n\n  const rowStyle: React.CSSProperties = {\n    width: '100%',\n    clear: 'both',\n  };\n\n  return (\n    <>\n      <div style={rowStyle}>\n        <h2 style={headingStyle}>{useInt.name}</h2>\n        <Clock useInt={useInt} />\n        {showSecondClock ? <Clock useInt={useInt} /> : null}\n      </div>\n    </>\n  );\n};\n\nstoriesOf('Animation/useHarmonicIntervalFn', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useHarmonicIntervalFn.md')} />)\n  .add('Demo', () => (\n    <>\n      <Demo useInt={useInterval} />\n      <br />\n      <br />\n      <br />\n      <br />\n      <br />\n      <Demo useInt={useHarmonicIntervalFn} />\n    </>\n  ));\n"
  },
  {
    "path": "stories/useHash.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useHash, useMount } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [hash, setHash] = useHash();\n\n  useMount(() => {\n    setHash('#/path/to/page?userId=123');\n  });\n\n  return (\n    <div>\n      <div>window.location.href:</div>\n      <div>\n        <pre>{window.location.href}</pre>\n      </div>\n      <div>Edit hash: </div>\n      <div>\n        <input style={{ width: '100%' }} value={hash} onChange={(e) => setHash(e.target.value)} />\n      </div>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useHash', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useHash.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useHover.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useHover } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const element = (hasHovered: boolean) => <div>Hover me! {hasHovered && 'Thanks!'}</div>;\n  const [hoverable, hovered] = useHover(element);\n\n  return (\n    <div>\n      {hoverable}\n      <div>{hovered ? 'HOVERED' : ''}</div>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useHover', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useHover.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useHoverDirty.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useRef } from 'react';\nimport { useHoverDirty } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const ref = useRef(null);\n  const isHovered = useHoverDirty(ref);\n\n  return <div ref={ref}>{isHovered ? '😁' : '☹️'}</div>;\n};\n\nstoriesOf('Sensors/useHoverDirty', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useHover.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useIdle.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useIdle } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [idleDelay, setIdleDelay] = React.useState(3e3);\n  const isIdle = useIdle(idleDelay);\n\n  return (\n    <div>\n      Idle delay ms:{' '}\n      <input\n        type=\"number\"\n        value={idleDelay}\n        onChange={({ target }) => setIdleDelay(+target.value)}\n      />\n      <div>User is idle: {isIdle ? 'Yes' : 'No'}</div>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useIdle', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useIdle.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useIntersection.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useIntersection } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Spacer = () => (\n  <div\n    style={{\n      width: '200px',\n      height: '300px',\n      backgroundColor: 'whitesmoke',\n    }}\n  />\n);\n\nconst Demo = () => {\n  const intersectionRef = React.useRef(null);\n  const intersection = useIntersection(intersectionRef, {\n    root: null,\n    rootMargin: '0px',\n    threshold: 1,\n  });\n\n  return (\n    <div\n      style={{\n        width: '400px',\n        height: '400px',\n        backgroundColor: 'whitesmoke',\n        overflow: 'scroll',\n      }}>\n      Scroll me\n      <Spacer />\n      <div\n        ref={intersectionRef}\n        style={{\n          width: '100px',\n          height: '100px',\n          padding: '20px',\n          backgroundColor: 'palegreen',\n        }}>\n        {intersection && intersection.intersectionRatio < 1 ? 'Obscured' : 'Fully in view'}\n      </div>\n      <Spacer />\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useIntersection', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useIntersection.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useInterval.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useInterval, useBoolean } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [count, setCount] = React.useState(0);\n  const [delay, setDelay] = React.useState(1000);\n  const [isRunning, toggleIsRunning] = useBoolean(true);\n\n  useInterval(\n    () => {\n      setCount(count + 1);\n    },\n    isRunning ? delay : null\n  );\n\n  return (\n    <div>\n      <div>\n        delay: <input value={delay} onChange={(event) => setDelay(Number(event.target.value))} />\n      </div>\n      <h1>count: {count}</h1>\n      <div>\n        <button onClick={toggleIsRunning}>{isRunning ? 'stop' : 'start'}</button>\n      </div>\n    </div>\n  );\n};\n\nstoriesOf('Animation/useInterval', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useInterval.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useIsomorphicLayoutEffect.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport ShowDocs from './util/ShowDocs';\n\nstoriesOf('Lifecycle/useIsomorphicLayoutEffect', module).add('Docs', () => (\n  <ShowDocs md={require('../docs/useIsomorphicLayoutEffect.md')} />\n));\n"
  },
  {
    "path": "stories/useKey.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useKey } from '../src';\nimport { CenterStory } from './util/CenterStory';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [count, setCount] = React.useState(0);\n\n  const increment = () => setCount((currentCount) => ++currentCount);\n  const decrement = () => setCount((currentCount) => --currentCount);\n  const reset = () => setCount(() => 0);\n\n  useKey(']', increment);\n  useKey('[', decrement);\n  useKey('r', reset);\n\n  return (\n    <CenterStory>\n      <style dangerouslySetInnerHTML={{ __html: `code {color: red}` }} />\n      <p>\n        Try pressing <code>[</code>, <code>]</code>, and <code>r</code> to see the count incremented\n        and decremented.\n      </p>\n      <p>Count: {count}</p>\n    </CenterStory>\n  );\n};\n\nconst CounterDemo = () => {\n  const [count, setCount] = React.useState(0);\n  const increment = () => setCount((currentCount) => ++currentCount);\n  useKey('ArrowUp', increment);\n\n  return <div>Press arrow up: {count}</div>;\n};\n\nstoriesOf('Sensors/useKey', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useKey.md')} />)\n  .add('Demo', () => <Demo />)\n  .add('Simple counter', () => <CounterDemo />);\n"
  },
  {
    "path": "stories/useKeyPress.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useKeyPress } from '../src';\nimport { CenterStory } from './util/CenterStory';\nimport ShowDocs from './util/ShowDocs';\n\nconst keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];\n\nconst Demo = () => {\n  const states: boolean[] = [];\n  for (const key of keys) {\n    // eslint-disable-next-line react-hooks/rules-of-hooks\n    states.push(useKeyPress(key)[0]);\n  }\n\n  return (\n    <CenterStory>\n      <div style={{ textAlign: 'center' }}>\n        Try pressing numbers\n        <br />\n        {states.reduce(\n          (s, pressed, index) => s + (pressed ? (s ? ' + ' : '') + keys[index] : ''),\n          ''\n        )}\n      </div>\n    </CenterStory>\n  );\n};\n\nstoriesOf('Sensors/useKeyPress', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useKeyPress.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useKeyPressEvent.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useKeyboardJs, useKeyPressEvent } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [count, setCount] = React.useState(0);\n\n  const increment = () => {\n    console.log('INCREMENT');\n    setCount((currentCount) => ++currentCount);\n  };\n  const decrement = () => {\n    console.log('DECREMENT');\n    setCount((currentCount) => --currentCount);\n  };\n  const reset = () => setCount(() => 0);\n\n  useKeyPressEvent(']', increment);\n  useKeyPressEvent('[', decrement);\n  useKeyPressEvent('r', reset);\n\n  return (\n    <div>\n      <style dangerouslySetInnerHTML={{ __html: `code {color: red}` }} />\n      <p>\n        Try pressing <code>[</code>, <code>]</code>, and <code>r</code> to see the count incremented\n        and decremented.\n      </p>\n      <p>Count: {count}</p>\n    </div>\n  );\n};\n\nconst DemoKeyboardJs = () => {\n  const [count, setCount] = React.useState(0);\n\n  const increment = () => {\n    console.log('INCREMENT');\n    setCount((currentCount) => ++currentCount);\n  };\n  const decrement = () => {\n    console.log('DECREMENT');\n    setCount((currentCount) => --currentCount);\n  };\n  const reset = () => setCount(() => 0);\n\n  useKeyPressEvent('q + ]', increment, increment, useKeyboardJs as any);\n  useKeyPressEvent('q + [', decrement, decrement, useKeyboardJs as any);\n  useKeyPressEvent('q + r', reset, null, useKeyboardJs as any);\n\n  return (\n    <div>\n      <style dangerouslySetInnerHTML={{ __html: `code {color: red}` }} />\n      <p>\n        Try pressing <code>q + [</code>, <code>q + ]</code>, and <code>q + r</code> to see the count\n        incremented and decremented.\n      </p>\n      <p>Count: {count}</p>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useKeyPressEvent', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useKeyPressEvent.md')} />)\n  .add('Demo', () => <Demo />)\n  .add('KeyboardJs', () => <DemoKeyboardJs />);\n"
  },
  {
    "path": "stories/useKeyboardJs.story.tsx",
    "content": "import { text, withKnobs } from '@storybook/addon-knobs';\nimport { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport useKeyboardJs from '../src/useKeyboardJs';\nimport { CenterStory } from './util/CenterStory';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = ({ combo }) => {\n  const [pressed] = useKeyboardJs(combo);\n\n  return (\n    <CenterStory>\n      <div style={{ textAlign: 'center' }}>\n        Press{' '}\n        <code\n          style={{ color: 'red', background: '#f6f6f6', padding: '3px 6px', borderRadius: '3px' }}>\n          {combo}\n        </code>{' '}\n        combo\n        <br />\n        <br />\n        <div style={{ fontSize: '4em' }}>{pressed ? '💋' : ''}</div>\n      </div>\n    </CenterStory>\n  );\n};\n\nstoriesOf('Sensors/useKeyboardJs', module)\n  .addDecorator(withKnobs)\n  .add('Docs', () => <ShowDocs md={require('../docs/useKeyboardJs.md')} />)\n  .add('Demo', () => {\n    const combo = text('Combo', 'i + l + u');\n    return <Demo combo={combo} />;\n  });\n"
  },
  {
    "path": "stories/useLatest.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useLatest } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [count, setCount] = React.useState(0);\n  const latestCount = useLatest(count);\n  const timeoutMs = 3000;\n\n  function handleAlertClick() {\n    setTimeout(() => {\n      alert(`Latest count value: ${latestCount.current}`);\n    }, timeoutMs);\n  }\n\n  return (\n    <div>\n      <p>You clicked {count} times</p>\n      <button onClick={() => setCount(count + 1)}>Click me</button>\n      <button onClick={handleAlertClick}>Show alert in {timeoutMs / 1000}s</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useLatest', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useLatest.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useLifecycles.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useLifecycles } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  useLifecycles(\n    () => console.log('MOUNTED'),\n    () => console.log('UNMOUNTED')\n  );\n  return null;\n};\n\nstoriesOf('Lifecycle/useLifecycles', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useLifecycles.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useList.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useList } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [\n    list,\n    { set, push, updateAt, insertAt, update, updateFirst, sort, filter, removeAt, clear, reset },\n  ] = useList([1, 2, 3, 4, 5]);\n\n  return (\n    <div>\n      <button onClick={() => set([1, 2, 3])}>Set to [1, 2, 3]</button>\n      <br />\n      <button onClick={() => push(Date.now())}>Push timestamp</button>\n      <br />\n      <button onClick={() => insertAt(1, Date.now())}>Insert new value at index 1</button>\n      <br />\n      <button onClick={() => updateAt(1, Date.now())}>Update value at index 1</button>\n      <br />\n      <button onClick={() => removeAt(1)}>Remove element at index 1</button>\n      <br />\n      <button onClick={() => filter((item) => item % 2 === 0)}>Filter even values</button>\n      <br />\n      <button onClick={() => update((item) => item % 2 === 0, Date.now())}>\n        Update all even values with timestamp\n      </button>\n      <br />\n      <button onClick={() => updateFirst((item) => item % 2 === 0, Date.now())}>\n        Update first even value with timestamp\n      </button>\n      <br />\n      <button onClick={() => sort((a, b) => a - b)}>Sort ascending</button>\n      <br />\n      <button onClick={() => sort((a, b) => b - a)}>Sort descending</button>\n      <br />\n      <button onClick={clear}>Clear</button>\n      <br />\n      <button onClick={reset}>Reset</button>\n      <br />\n      <pre>{JSON.stringify(list, null, 2)}</pre>\n    </div>\n  );\n};\n\ninterface UpsertDemoType {\n  id: string;\n  text: string;\n}\n\nconst upsertPredicate = (a: UpsertDemoType, b: UpsertDemoType) => a.id === b.id;\nconst upsertInitialItems: UpsertDemoType[] = [\n  { id: '1', text: 'Sample' },\n  { id: '2', text: 'Example' },\n];\nconst UpsertDemo = () => {\n  const [list, { upsert, reset, removeAt }] = useList(upsertInitialItems);\n\n  return (\n    <div style={{ display: 'inline-flex', flexDirection: 'column' }}>\n      {list.map((item, index) => (\n        <div key={item.id}>\n          <input\n            value={item.text}\n            onChange={(e) => upsert(upsertPredicate, { ...item, text: e.target.value })}\n          />\n          <button onClick={() => removeAt(index)}>Remove</button>\n        </div>\n      ))}\n      <button\n        onClick={() => upsert(upsertPredicate, { id: (list.length + 1).toString(), text: '' })}>\n        Add item\n      </button>\n      <button onClick={() => reset()}>Reset</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useList', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useList.md')} />)\n  .add('Demo', () => <Demo />)\n  .add('Upsert Demo', () => <UpsertDemo />);\n"
  },
  {
    "path": "stories/useLocalStorage.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useLocalStorage } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [value, setValue] = useLocalStorage('hello-key', 'foo');\n  const [removableValue, setRemovableValue, remove] = useLocalStorage('removeable-key');\n\n  return (\n    <div>\n      <div>Value: {value}</div>\n      <button onClick={() => setValue('bar')}>bar</button>\n      <button onClick={() => setValue('baz')}>baz</button>\n      <br />\n      <br />\n      <div>Removable Value: {removableValue}</div>\n      <button onClick={() => setRemovableValue('foo')}>foo</button>\n      <button onClick={() => setRemovableValue('bar')}>bar</button>\n      <button onClick={() => remove()}>Remove</button>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useLocalStorage', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useLocalStorage.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useLocation.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useLocation } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst go = (page) => window.history.pushState({}, '', page);\n\nconst Demo = () => {\n  const state = useLocation();\n\n  return (\n    <div>\n      <button onClick={() => go('page-1')}>Page 1</button>\n      <button onClick={() => go('page-2')}>Page 2</button>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useLocation', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useLocation.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useLockBodyScroll.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useRef } from 'react';\nimport Frame from 'react-frame-component';\nimport { useLockBodyScroll, useToggle } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [locked, toggleLocked] = useToggle(false);\n  useLockBodyScroll(locked);\n\n  return (\n    <div style={{ height: '200vh' }}>\n      <button onClick={() => toggleLocked()} style={{ position: 'fixed', left: 0 }}>\n        {locked ? 'Unlock' : 'Lock'}\n      </button>\n    </div>\n  );\n};\n\nconst AnotherComponent = () => {\n  const [locked, toggleLocked] = useToggle(false);\n  useLockBodyScroll(locked);\n\n  return (\n    <button onClick={() => toggleLocked()} style={{ position: 'fixed', left: 0, top: 40 }}>\n      {locked ? 'Unlock' : 'Lock'}\n    </button>\n  );\n};\n\nconst IframeComponent = () => {\n  const [mainLocked, toggleMainLocked] = useToggle(false);\n  const [iframeLocked, toggleIframeLocked] = useToggle(false);\n  const iframeElementRef = useRef<HTMLIFrameElement>(null);\n\n  useLockBodyScroll(mainLocked);\n  useLockBodyScroll(iframeLocked, iframeElementRef);\n\n  return (\n    <div style={{ height: '200vh' }}>\n      <Frame style={{ height: '50vh', width: '50vw' }}>\n        <div style={{ height: '200vh' }} ref={iframeElementRef}>\n          <button onClick={() => toggleMainLocked()} style={{ position: 'fixed', left: 0, top: 0 }}>\n            {mainLocked ? 'Unlock' : 'Lock'} main window scroll\n          </button>\n          <button\n            onClick={() => toggleIframeLocked()}\n            style={{ position: 'fixed', left: 0, top: 64 }}>\n            {iframeLocked ? 'Unlock' : 'Lock'} iframe window scroll\n          </button>\n        </div>\n      </Frame>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useLockBodyScroll', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useLockBodyScroll.md')} />)\n  .add('Demo', () => <Demo />)\n  .add('Two hooks on page', () => (\n    <>\n      <AnotherComponent />\n      <Demo />\n      <IframeComponent />\n    </>\n  ))\n  .add('Iframe', () => <IframeComponent />);\n"
  },
  {
    "path": "stories/useLogger.story.tsx",
    "content": "import { boolean, text, withKnobs } from '@storybook/addon-knobs';\nimport { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCounter, useLogger } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = (props) => {\n  const [state, { inc }] = useCounter(0);\n\n  useLogger('Demo', props, state);\n\n  return (\n    <>\n      <p style={{ fontWeight: props.bold ? 'bold' : 'normal' }}>{props.title}</p>\n      <button onClick={() => inc()}>Update state ({state})</button>\n    </>\n  );\n};\n\nstoriesOf('Lifecycle/useLogger', module)\n  .addDecorator(withKnobs)\n  .add('Docs', () => <ShowDocs md={require('../docs/useLogger.md')} />)\n  .add('Demo', () => {\n    const props = {\n      title: text('title', 'Open the developer console to see logs'),\n      bold: boolean('bold', false),\n    };\n\n    return <Demo {...props} />;\n  });\n"
  },
  {
    "path": "stories/useLongPress.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useLongPress } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const onLongPress = () => {\n    console.log('calls callback after long pressing 300ms');\n  };\n\n  const defaultOptions = {\n    isPreventDefault: true,\n    delay: 300,\n  };\n  const longPressEvent = useLongPress(onLongPress, defaultOptions);\n\n  return <button {...longPressEvent}>useLongPress</button>;\n};\n\nstoriesOf('Sensors/useLongPress', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useLongPress.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMap.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMap } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [map, { set, remove, reset }] = useMap({\n    hello: 'there',\n  });\n\n  return (\n    <div>\n      <button onClick={() => set(String(Date.now()), new Date().toJSON())}>Add</button>\n      <button onClick={() => reset()}>Reset</button>\n      <button onClick={() => remove('hello')} disabled={!map.hello}>\n        Remove 'hello'\n      </button>\n      <pre>{JSON.stringify(map, null, 2)}</pre>\n    </div>\n  );\n};\n\nstoriesOf('State/useMap', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMap.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMeasure.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport React from 'react';\nimport { useMeasure } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [ref, state] = useMeasure();\n\n  return (\n    <>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      <div ref={ref} style={{ background: 'red' }}>\n        resize me\n      </div>\n    </>\n  );\n};\n\nstoriesOf('Sensors/useMeasure', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMeasure.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMedia.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMedia } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const isWide = useMedia('(min-width: 480px)');\n\n  return <div>Screen is wide: {isWide ? 'Yes' : 'No'}</div>;\n};\n\nstoriesOf('Sensors/useMedia', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMedia.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMediaDevices.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMediaDevices } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const state = useMediaDevices();\n\n  return <pre>{JSON.stringify(state, null, 2)}</pre>;\n};\n\nstoriesOf('Sensors/useMediaDevices', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMediaDevices.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMediatedState.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMediatedState } from '../src/useMediatedState';\nimport ShowDocs from './util/ShowDocs';\n\nconst inputMediator = (s) => s.replace(/[\\s]+/g, ' ');\nconst Demo = () => {\n  const [state, setState] = useMediatedState(inputMediator, '');\n\n  return (\n    <div>\n      <div>You will not be able to enter more than one space</div>\n      <input\n        type=\"text\"\n        min=\"0\"\n        max=\"10\"\n        value={state}\n        onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {\n          setState(ev.target.value);\n        }}\n      />\n    </div>\n  );\n};\n\nstoriesOf('State/useMediatedState', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMediatedState.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMethods.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMethods } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst initialState = {\n  count: 0,\n};\n\nfunction createMethods(state) {\n  return {\n    reset() {\n      return initialState;\n    },\n    increment() {\n      return { ...state, count: state.count + 1 };\n    },\n    decrement() {\n      return { ...state, count: state.count - 1 };\n    },\n  };\n}\n\nconst Demo = () => {\n  const [state, methods] = useMethods(createMethods, initialState);\n\n  return (\n    <>\n      <p>Count: {state.count}</p>\n      <button onClick={methods.decrement}>-</button>\n      <button onClick={methods.increment}>+</button>\n    </>\n  );\n};\n\nstoriesOf('State/useMethods', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMethods.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMotion.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMotion } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const state = useMotion();\n\n  return <pre>{JSON.stringify(state, null, 2)}</pre>;\n};\n\nstoriesOf('Sensors/useMotion', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMotion.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMount.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMount } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  useMount(() => alert('MOUNTED'));\n\n  return (\n    <div>\n      <code>useMount()</code> hook can be used to perform a side-effect when component is mounted.\n    </div>\n  );\n};\n\nstoriesOf('Lifecycle/useMount', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMount.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMountedState.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMountedState } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const isMounted = useMountedState();\n  const [, updateState] = React.useState();\n\n  requestAnimationFrame(updateState);\n\n  return <div>This component is {isMounted() ? 'MOUNTED' : 'NOT MOUNTED'}</div>;\n};\n\nstoriesOf('Lifecycle/useMountedState', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMountedState.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMouse.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMouse } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const ref = React.useRef(null);\n  const state = useMouse(ref);\n\n  return (\n    <>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      <br />\n      <br />\n      <div\n        ref={ref}\n        style={{\n          position: 'relative',\n          width: '400px',\n          height: '400px',\n          backgroundColor: 'whitesmoke',\n        }}>\n        <span\n          style={{\n            position: 'absolute',\n            left: `${state.elX}px`,\n            top: `${state.elY}px`,\n            pointerEvents: 'none',\n            transform: 'scale(4)',\n          }}>\n          🐭\n        </span>\n      </div>\n    </>\n  );\n};\n\nstoriesOf('Sensors/useMouse', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMouse.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMouseHovered.story.tsx",
    "content": "import { boolean, withKnobs } from '@storybook/addon-knobs';\nimport { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMouseHovered } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = ({ whenHovered, bound }: any) => {\n  const ref = React.useRef(null);\n  const state = useMouseHovered(ref, { whenHovered, bound });\n\n  return (\n    <>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      <br />\n      <br />\n      <div\n        ref={ref}\n        style={{\n          position: 'relative',\n          width: '400px',\n          height: '400px',\n          backgroundColor: 'whitesmoke',\n        }}>\n        <span\n          style={{\n            position: 'absolute',\n            left: `${state.elX}px`,\n            top: `${state.elY}px`,\n            pointerEvents: 'none',\n            transform: 'scale(4)',\n          }}>\n          🐭\n        </span>\n      </div>\n    </>\n  );\n};\n\nstoriesOf('Sensors/useMouseHovered', module)\n  .addDecorator(withKnobs)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMouse.md')} />)\n  .add('Demo', () => {\n    const bound = boolean('bound', false);\n    const whenHovered = boolean('whenHovered', false);\n    return <Demo whenHovered={whenHovered} bound={bound} />;\n  });\n"
  },
  {
    "path": "stories/useMouseWheel.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMouseWheel } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const mouseWheel = useMouseWheel();\n  return (\n    <>\n      <h3>delta Y Scrolled: {mouseWheel}</h3>\n    </>\n  );\n};\n\nstoriesOf('Sensors/useMouseWheel', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMouseWheel.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useMultiStateValidator.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useMultiStateValidator } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst DemoStateValidator = (s: number[]) => [s.every((num: number) => !(num % 2))] as [boolean];\nconst Demo = () => {\n  const [state1, setState1] = React.useState<number>(1);\n  const [state2, setState2] = React.useState<number>(1);\n  const [state3, setState3] = React.useState<number>(1);\n  const [[isValid]] = useMultiStateValidator([state1, state2, state3], DemoStateValidator);\n\n  return (\n    <div>\n      <div>Below fields will be valid if all of them is even</div>\n      <br />\n      <input\n        type=\"number\"\n        min=\"1\"\n        max=\"10\"\n        value={state1}\n        onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {\n          setState1(ev.target.value as unknown as number);\n        }}\n      />\n      <input\n        type=\"number\"\n        min=\"1\"\n        max=\"10\"\n        value={state2}\n        onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {\n          setState2(ev.target.value as unknown as number);\n        }}\n      />\n      <input\n        type=\"number\"\n        min=\"1\"\n        max=\"10\"\n        value={state3}\n        onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {\n          setState3(ev.target.value as unknown as number);\n        }}\n      />\n      {isValid !== undefined && (\n        <span style={{ marginLeft: 24 }}>{isValid ? 'Valid!' : 'Invalid'}</span>\n      )}\n    </div>\n  );\n};\n\nstoriesOf('State/useMultiStateValidator', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useMultiStateValidator.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useNetwork.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useEffect } from 'react';\nimport { useNetworkState } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const state = useNetworkState();\n\n  useEffect(() => {\n    console.log(state);\n  }, [state]);\n\n  return (\n    <div>\n      <div>Since JSON do not output `undefined` fields look the console to see whole the state</div>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useNetworkState', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useNetworkState.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useObservable.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { BehaviorSubject } from 'rxjs';\nimport { useObservable } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst counter$ = new BehaviorSubject(0);\nconst Demo = () => {\n  const value = useObservable(counter$, 0);\n\n  return <button onClick={() => counter$.next(value! + 1)}>Clicked {value} times</button>;\n};\n\nstoriesOf('State/useObservable', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useObservable.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useOrientation.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useOrientation } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const state = useOrientation();\n\n  return <pre>{JSON.stringify(state, null, 2)}</pre>;\n};\n\nstoriesOf('Sensors/useOrientation', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useOrientation.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/usePageLeave.story.tsx",
    "content": "import { action } from '@storybook/addon-actions';\nimport { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { usePageLeave } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  usePageLeave(action('onPageLeave'));\n\n  return (\n    <div>\n      Try leaving the page and see logs in <code>Actions</code> tab.\n    </div>\n  );\n};\n\nstoriesOf('Sensors/usePageLeave', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/usePageLeave.md')} />)\n  .add('Default', () => <Demo />);\n"
  },
  {
    "path": "stories/usePermission.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { usePermission } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const state = usePermission({ name: 'microphone' });\n\n  return <pre>{JSON.stringify(state, null, 2)}</pre>;\n};\n\nstoriesOf('Side effects/usePermission', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/usePermission.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/usePinchZoom.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { usePinchZoom } from '../src';\nimport { ZoomState } from '../src/usePinchZoom';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [scale, setState] = useState(1);\n  const scaleRef = useRef();\n  const { zoomingState, pinchState } = usePinchZoom(scaleRef);\n\n  useEffect(() => {\n    if (zoomingState === ZoomState.ZOOMING_IN) {\n      // perform zoom in scaling\n      setState(scale + 0.1);\n    } else if (zoomingState === ZoomState.ZOOMING_OUT) {\n      // perform zoom out in scaling\n      setState(scale - 0.1);\n    }\n  }, [zoomingState, pinchState]);\n\n  return (\n    <div ref={scaleRef}>\n      <img\n        src=\"https://www.olympus-imaging.co.in/content/000107506.jpg\"\n        style={{\n          zoom: scale,\n        }}\n        alt=\"scale img\"\n      />\n    </div>\n  );\n};\n\nstoriesOf('Sensors/usePinchZoom', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/usePinchZoom.md')} />)\n  .add('Default', () => <Demo />);\n"
  },
  {
    "path": "stories/usePrevious.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { usePrevious } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [count, setCount] = React.useState(0);\n  const prevCount = usePrevious(count);\n\n  return (\n    <div>\n      <p>\n        Now: {count}, before: {String(prevCount)}\n      </p>\n      <button onClick={() => setCount((value) => value + 1)}>+</button>\n      <button onClick={() => setCount((value) => value - 1)}>-</button>\n    </div>\n  );\n};\n\nstoriesOf('State/usePrevious', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/usePrevious.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/usePreviousDistinct.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { usePreviousDistinct, useCounter } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [count, { inc: relatedInc }] = useCounter(0);\n  const [unrelatedCount, { inc }] = useCounter(0);\n  const prevCount = usePreviousDistinct(count);\n\n  return (\n    <p>\n      Now: {count}, before: {prevCount}\n      <button onClick={() => relatedInc()}>Increment</button>\n      Unrelated: {unrelatedCount}\n      <button onClick={() => inc()}>Increment Unrelated</button>\n    </p>\n  );\n};\n\nstoriesOf('State/usePreviousDistinct', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/usePreviousDistinct.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/usePromise.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useBoolean, useNumber, usePromise } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst { useState, useEffect } = React;\n\nconst DemoInner = ({ promise }) => {\n  const safePromise = usePromise();\n  const [value, setValue] = useState<number>(-1);\n  useEffect(() => {\n    safePromise(promise).then(setValue);\n  }, [promise]);\n\n  return <div>{value === -1 ? 'Resolving value...' : 'Value: ' + value}</div>;\n};\n\nconst Demo = () => {\n  const [mounted, toggleMounted] = useBoolean(true);\n  const [num, { inc }] = useNumber();\n  const promise = new Promise((r) => setTimeout(() => r(num), 1_000));\n\n  return (\n    <div>\n      <p>This demo provides a number in a promise that resolves in 1sec to a child component.</p>\n      <button onClick={() => toggleMounted()}>{mounted ? 'Unmount' : 'Mount'}</button>\n      <button onClick={() => inc()}>Increment ({num})</button>\n      <br />\n      {mounted && <DemoInner promise={promise} />}\n    </div>\n  );\n};\n\nstoriesOf('Lifecycle/usePromise', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/usePromise.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useQueue.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useQueue } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const { add, remove, first, last, size } = useQueue();\n  return (\n    <div>\n      <ul>\n        <li>first: {first}</li>\n        <li>last: {last}</li>\n        <li>size: {size}</li>\n      </ul>\n      <button onClick={() => add((last || 0) + 1)}>Add</button>\n      <button onClick={() => remove()}>Remove</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useQueue', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useQueue.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useRaf.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useRaf } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const frames = useRaf(5000, 1000);\n\n  return <div>Elapsed: {frames}</div>;\n};\n\nstoriesOf('Animation/useRaf', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useRaf.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useRafLoop.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useRafLoop, useUpdate } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [ticks, setTicks] = React.useState(0);\n  const [lastCall, setLastCall] = React.useState(0);\n  const update = useUpdate();\n\n  const [loopStop, loopStart, isActive] = useRafLoop((time) => {\n    setTicks((ticks) => ticks + 1);\n    setLastCall(time);\n  });\n\n  return (\n    <div>\n      <div>RAF triggered: {ticks} (times)</div>\n      <div>Last high res timestamp: {lastCall}</div>\n      <br />\n      <button\n        onClick={() => {\n          isActive() ? loopStop() : loopStart();\n          update();\n        }}>\n        {isActive() ? 'STOP' : 'START'}\n      </button>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useRafLoop', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useRafLoop.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useRafState.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useRafState, useMount } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [state, setState] = useRafState({ x: 0, y: 0 });\n\n  useMount(() => {\n    const onMouseMove = (event: MouseEvent) => {\n      setState({ x: event.clientX, y: event.clientY });\n    };\n    const onTouchMove = (event: TouchEvent) => {\n      setState({ x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY });\n    };\n\n    document.addEventListener('mousemove', onMouseMove);\n    document.addEventListener('touchmove', onTouchMove);\n\n    return () => {\n      document.removeEventListener('mousemove', onMouseMove);\n      document.removeEventListener('touchmove', onTouchMove);\n    };\n  });\n\n  return <pre>{JSON.stringify(state, null, 2)}</pre>;\n};\n\nstoriesOf('State/useRafState', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useRafState.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useRendersCount.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useRendersCount } from '../src/useRendersCount';\nimport useUpdate from '../src/useUpdate';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const update = useUpdate();\n  const rendersCount = useRendersCount();\n\n  return (\n    <div>\n      <span>Renders count: {rendersCount}</span>\n      <br />\n      <button onClick={update}>re-render</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useRendersCount', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useRendersCount.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useScratch.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useScratch } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [ref, state] = useScratch();\n\n  const blockStyle: React.CSSProperties = {\n    position: 'relative',\n    width: 400,\n    height: 400,\n    border: '1px solid tomato',\n  };\n\n  const preStyle: React.CSSProperties = {\n    pointerEvents: 'none',\n    userSelect: 'none',\n  };\n\n  let { x = 0, y = 0, dx = 0, dy = 0 } = state;\n  if (dx < 0) [x, dx] = [x + dx, -dx];\n  if (dy < 0) [y, dy] = [y + dy, -dy];\n\n  const rectangleStyle: React.CSSProperties = {\n    position: 'absolute',\n    left: x,\n    top: y,\n    width: dx,\n    height: dy,\n    border: '1px solid tomato',\n    pointerEvents: 'none',\n    userSelect: 'none',\n  };\n\n  return (\n    <div ref={ref} style={blockStyle}>\n      <pre style={preStyle}>{JSON.stringify(state, null, 4)}</pre>\n      {state.isScratching && <div style={rectangleStyle} />}\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useScratch', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useScratch.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useScroll.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useScroll } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const scrollRef = React.useRef(null);\n  const { x, y } = useScroll(scrollRef);\n\n  return (\n    <>\n      <div>x: {x}</div>\n      <div>y: {y}</div>\n      <div\n        ref={scrollRef}\n        style={{\n          width: '400px',\n          height: '400px',\n          backgroundColor: 'whitesmoke',\n          overflow: 'scroll',\n        }}>\n        <div style={{ width: '2000px', height: '2000px' }}>Scroll me</div>\n      </div>\n    </>\n  );\n};\n\nstoriesOf('Sensors/useScroll', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useScroll.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useScrollbarWidth.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useScrollbarWidth } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const sbw = useScrollbarWidth();\n\n  return (\n    <div>\n      {sbw === undefined\n        ? `DOM is not ready yet, SBW detection delayed`\n        : `Browser's scrollbar width is ${sbw}px`}\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useScrollbarWidth', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useScroll.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useScrolling.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useScrolling } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const scrollRef = React.useRef(null);\n  const scrolling = useScrolling(scrollRef);\n\n  return (\n    <>\n      {<div>{scrolling ? 'Scrolling' : 'Not scrolling'}</div>}\n      <br />\n      <div\n        ref={scrollRef}\n        style={{\n          width: '400px',\n          height: '400px',\n          backgroundColor: 'whitesmoke',\n          overflow: 'scroll',\n        }}>\n        <div style={{ width: '2000px', height: '2000px' }}>Scroll me</div>\n      </div>\n    </>\n  );\n};\n\nstoriesOf('Sensors/useScrolling', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useScrolling.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useSearchParam.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useSearchParam } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const edit = useSearchParam('edit');\n\n  return (\n    <div>\n      <div>edit: {edit || '🤷‍♂️'}</div>\n      <div>\n        <button\n          onClick={() => window.history.pushState({}, '', window.location.pathname + '?edit=123')}>\n          Edit post 123 (?edit=123)\n        </button>\n      </div>\n      <div>\n        <button\n          onClick={() => window.history.pushState({}, '', window.location.pathname + '?edit=999')}>\n          Edit post 999 (?edit=999)\n        </button>\n      </div>\n      <div>\n        <button onClick={() => window.history.pushState({}, '', window.location.pathname)}>\n          Close modal\n        </button>\n      </div>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useSearchParam', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useSearchParam.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useSessionStorage.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useSessionStorage } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [value, setValue] = useSessionStorage('hello-key', 'foo');\n\n  return (\n    <div>\n      <div>Value: {value}</div>\n      <button onClick={() => setValue('bar')}>bar</button>\n      <button onClick={() => setValue('baz')}>baz</button>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useSessionStorage', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useSessionStorage.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useSet.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useSet } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [set, { add, has, remove, reset, clear, toggle }] = useSet(new Set(['hello']));\n\n  return (\n    <div>\n      <button onClick={() => add(String(Date.now()))}>Add</button>\n      <button onClick={() => reset()}>Reset</button>\n      <button onClick={() => clear()}>Clear</button>\n      <button onClick={() => remove('hello')} disabled={!has('hello')}>\n        Remove 'hello'\n      </button>\n      <button onClick={() => toggle('hello')}>Toggle 'hello'</button>\n      <pre>{JSON.stringify(Array.from(set), null, 2)}</pre>\n    </div>\n  );\n};\n\nstoriesOf('State/useSet', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useSet.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useSetState.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useSetState } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [state, setState] = useSetState({});\n\n  return (\n    <div>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      <button onClick={() => setState({ hello: 'world' })}>hello</button>\n      <button onClick={() => setState({ foo: 'bar' })}>foo</button>\n      <button\n        onClick={() => {\n          setState((prevState) => ({\n            count: prevState.count === undefined ? 0 : prevState.count + 1,\n          }));\n        }}>\n        increment\n      </button>\n    </div>\n  );\n};\n\nstoriesOf('State/useSetState', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useSetState.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useShallowCompareEffect.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCounter, useShallowCompareEffect } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [countNormal, { inc: incNormal }] = useCounter(0);\n  const [countShallow, { inc: incShallow }] = useCounter(0);\n  const [countDeep, { inc: incDeep }] = useCounter(0);\n  const options = { nested: { max: 500 } };\n\n  React.useEffect(() => {\n    if (countNormal < options.nested.max) {\n      incNormal();\n    }\n  }, [options.nested]);\n\n  useShallowCompareEffect(() => {\n    if (countNormal < options.nested.max) {\n      incShallow();\n    }\n  }, [options.nested]);\n\n  useShallowCompareEffect(() => {\n    if (countNormal < options.nested.max) {\n      incDeep();\n    }\n  }, [options]);\n\n  return (\n    <div>\n      <p>useEffect: {countNormal}</p>\n      <p>useShallowCompareEffect 1st level change: {countShallow}</p>\n      <p>useShallowCompareEffect 2nd level change: {countDeep}</p>\n    </div>\n  );\n};\n\nstoriesOf('Lifecycle/useShallowCompareEffect', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useShallowCompareEffect.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useSize.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useSize } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [sized, state] = useSize(({ width: currentWidth }) => (\n    <div style={{ background: 'red' }}>Size me up! ({currentWidth}px)</div>\n  ));\n\n  return (\n    <div>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      {sized}\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useSize', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useSize.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useSlider.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useSlider } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const ref = React.useRef(null);\n  const state = useSlider(ref, {\n    onScrubStop: (value) => {\n      console.log('onScrubStop', value);\n    },\n  });\n\n  return (\n    <div>\n      <div ref={ref} style={{ position: 'relative', background: 'yellow', padding: 4 }}>\n        <p style={{ margin: 0, textAlign: 'center' }}>Slide me</p>\n        <div\n          style={{\n            position: 'absolute',\n            top: 0,\n            left: 100 * state.value + '%',\n            transform: 'scale(2)',\n          }}>\n          {state.isSliding ? '🏂' : '🎿'}\n        </div>\n      </div>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n    </div>\n  );\n};\n\nconst DemoVertical = () => {\n  const ref = React.useRef(null);\n  const state = useSlider(ref, { vertical: true });\n\n  return (\n    <div>\n      <div\n        ref={ref}\n        style={{ position: 'relative', background: 'yellow', padding: 4, width: 30, height: 400 }}>\n        <p style={{ margin: 0, textAlign: 'center' }}>Slide me</p>\n        <div\n          style={{\n            position: 'absolute',\n            left: 0,\n            top: 100 * state.value + '%',\n            transform: 'scale(2)',\n          }}>\n          {state.isSliding ? '🏂' : '🎿'}\n        </div>\n      </div>\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n    </div>\n  );\n};\n\nstoriesOf('UI/useSlider', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useSlider.md')} />)\n  .add('Horizontal', () => <Demo />)\n  .add('Vertical', () => <DemoVertical />);\n"
  },
  {
    "path": "stories/useSpeech.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useSpeech } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const voices = window.speechSynthesis.getVoices();\n  const state = useSpeech('Hello world!', { rate: 0.8, pitch: 0.5, voice: voices[0] });\n\n  return <pre>{JSON.stringify(state, null, 2)}</pre>;\n};\n\nstoriesOf('UI/useSpeech', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useSpeech.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useSpring.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport useSpring from '../src/useSpring';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [target, setTarget] = (React as any).useState(50);\n  const value = useSpring(target);\n\n  return (\n    <div>\n      {value}\n      <br />\n      <button onClick={() => setTarget(0)}>Set 0</button>\n      <button onClick={() => setTarget(100)}>Set 100</button>\n    </div>\n  );\n};\n\nstoriesOf('Animation/useSpring', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useSpring.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useStartTyping.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useStartTyping } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const input = React.useRef(null);\n  useStartTyping(() => {\n    if (input.current) {\n      input.current.focus();\n    }\n  });\n\n  return (\n    <div>\n      <p>Start typing, and below field will get focused.</p>\n      <input ref={input} />\n\n      <br />\n      <hr />\n\n      <p>Try focusing below elements and see what happens.</p>\n      <button>When button is focused, it will lose it.</button>\n      <br />\n      <br />\n      <input />\n      <br />\n      <br />\n      <textarea>Editable textarea</textarea>\n      <br />\n      <br />\n      <div contentEditable={true}>Editable DIV</div>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useStartTyping', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useStartTyping.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useStateList.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useRef } from 'react';\nimport { useStateList } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst stateSet = ['first', 'second', 'third', 'fourth', 'fifth'];\n\nconst Demo = () => {\n  const { state, prev, next, setStateAt, setState, currentIndex, isFirst, isLast } =\n    useStateList(stateSet);\n  const indexInput = useRef<HTMLInputElement>(null);\n  const stateInput = useRef<HTMLInputElement>(null);\n\n  return (\n    <div>\n      <pre>\n        {state} [index: {currentIndex}], [isFirst: {isFirst}], [isLast: {isLast}]\n      </pre>\n      <button onClick={() => prev()}>prev</button>\n      <br />\n      <button onClick={() => next()}>next</button>\n      <br />\n      <input type=\"text\" ref={indexInput} style={{ width: 120 }} />\n      <button onClick={() => setStateAt(indexInput.current!.value as unknown as number)}>\n        set state by index\n      </button>\n      <br />\n      <input type=\"text\" ref={stateInput} style={{ width: 120 }} />\n      <button onClick={() => setState(stateInput.current!.value)}> set state by value</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useStateList', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useStateList.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useStateValidator.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport useStateValidator from '../src/useStateValidator';\nimport ShowDocs from './util/ShowDocs';\n\nconst DemoStateValidator = (s) =>\n  [s === '' ? undefined : (s * 1) % 2 === 0] as [boolean | undefined];\nconst Demo = () => {\n  const [state, setState] = React.useState<number>(0);\n  const [[isValid]] = useStateValidator(state, DemoStateValidator);\n\n  return (\n    <div>\n      <div>Below field is valid only if number is even</div>\n      <input\n        type=\"number\"\n        min=\"0\"\n        max=\"10\"\n        value={state}\n        onChange={(ev: React.ChangeEvent<HTMLInputElement>) => {\n          setState(ev.target.value as unknown as number);\n        }}\n      />\n      {isValid !== undefined && <span>{isValid ? 'Valid!' : 'Invalid'}</span>}\n    </div>\n  );\n};\n\nstoriesOf('State/useStateValidator', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useStateValidator.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useStateWithHistory.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCallback, useRef } from 'react';\nimport { useCounter, useStateWithHistory } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [state, setState, history] = useStateWithHistory('', 10, ['hello', 'world']);\n  const inputRef = useRef<HTMLInputElement | null>(null);\n\n  const [stepSize, { set: setStepSize }] = useCounter(1, 3, 1);\n\n  const handleFormSubmit = useCallback(\n    (e: React.FormEvent<HTMLFormElement>) => {\n      e.preventDefault();\n      state !== inputRef.current!.value && setState(inputRef.current!.value);\n    },\n    [state]\n  );\n\n  const handleBackClick = useCallback(\n    (e: React.MouseEvent<HTMLButtonElement>) => {\n      if (e.currentTarget.disabled) {\n        return;\n      }\n\n      window.history.back(stepSize);\n    },\n    [history, stepSize]\n  );\n\n  const handleForwardClick = useCallback(\n    (e: React.MouseEvent<HTMLButtonElement>) => {\n      if (e.currentTarget.disabled) {\n        return;\n      }\n\n      window.history.forward(stepSize);\n    },\n    [history, stepSize]\n  );\n\n  const handleStepSizeChange = useCallback(\n    (e: React.FormEvent<HTMLInputElement>) => {\n      setStepSize((e.currentTarget.value as any) * 1);\n    },\n    [stepSize]\n  );\n\n  return (\n    <div>\n      <div>\n        <form onSubmit={handleFormSubmit} style={{ display: 'inline-block' }}>\n          <input type=\"text\" ref={inputRef} />\n          <button>Submit new state</button>\n        </form>\n      </div>\n\n      <div style={{ marginTop: 8 }}>\n        Current state: <span>{state}</span>\n      </div>\n      <div style={{ marginTop: 8 }}>\n        <button onClick={handleBackClick} disabled={!window.history.position}>\n          &lt; Back\n        </button>\n        <button\n          onClick={handleForwardClick}\n          disabled={window.history.position >= window.history.window.history.length - 1}>\n          Forward &gt;\n        </button>\n        &nbsp; Step size:&nbsp;\n        <input type=\"number\" value={stepSize} min={1} max={3} onChange={handleStepSizeChange} />\n      </div>\n\n      <div style={{ marginTop: 8 }}>\n        <div>Current history</div>\n        <div\n          dangerouslySetInnerHTML={{\n            __html: JSON.stringify(window.history.history, null, 2)\n              .replace(/\\n/g, '<br/>')\n              .replace(/ /g, '&nbsp;'),\n          }}\n        />\n      </div>\n    </div>\n  );\n};\n\nstoriesOf('State/useStateWithHistory', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useStateWithHistory.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useThrottle.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCounter, useThrottle } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [value, setValue] = React.useState('');\n  const throttledValue = useThrottle(value, 2000);\n  const [lastThrottledValue, setLastThrottledValue] = React.useState(throttledValue);\n  const [count, { inc }] = useCounter();\n\n  React.useEffect(() => {\n    if (lastThrottledValue !== throttledValue) {\n      setLastThrottledValue(throttledValue);\n      inc();\n    }\n  });\n\n  return (\n    <div style={{ width: 300, margin: '40px auto' }}>\n      <input\n        type=\"text\"\n        value={value}\n        placeholder=\"Throttled input\"\n        style={{ width: '100%' }}\n        onChange={({ currentTarget }) => {\n          setValue(currentTarget.value);\n        }}\n      />\n      <br />\n      <br />\n      <div>Throttled value: {throttledValue}</div>\n      <div>Times updated: {count}</div>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useThrottle', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useThrottle.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useThrottleFn.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCounter, useThrottleFn } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [value, setValue] = React.useState('');\n  const throttledValue = useThrottleFn((defaultValue) => defaultValue, 2000, [value]);\n  const [lastThrottledValue, setLastThrottledValue] = React.useState(throttledValue);\n  const [count, { inc }] = useCounter();\n\n  React.useEffect(() => {\n    if (lastThrottledValue !== throttledValue) {\n      setLastThrottledValue(throttledValue);\n      inc();\n    }\n  });\n\n  return (\n    <div style={{ width: 300, margin: '40px auto' }}>\n      <input\n        type=\"text\"\n        value={value}\n        placeholder=\"Throttled input\"\n        style={{ width: '100%' }}\n        onChange={({ currentTarget }) => {\n          setValue(currentTarget.value);\n        }}\n      />\n      <br />\n      <br />\n      <div>Throttled value: {throttledValue}</div>\n      <div>Times updated: {count}</div>\n    </div>\n  );\n};\n\nstoriesOf('Side effects/useThrottleFn', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useThrottle.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useTimeout.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useTimeout } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nfunction TestComponent(props: { ms?: number } = {}) {\n  const ms = props.ms || 5000;\n  const [isReady, cancel] = useTimeout(ms);\n\n  return (\n    <div>\n      {isReady() ? \"I'm reloaded after timeout\" : `I will be reloaded after ${ms / 1000}s`}\n      {isReady() === false ? <button onClick={cancel}>Cancel</button> : ''}\n    </div>\n  );\n}\n\nconst Demo = () => {\n  return (\n    <div>\n      <TestComponent />\n      <TestComponent ms={10000} />\n    </div>\n  );\n};\n\nstoriesOf('Animation/useTimeout', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useTimeout.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useTimeoutFn.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useCallback } from 'react';\nimport { useTimeoutFn } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [state, setState] = React.useState('Not called yet');\n\n  function fn() {\n    setState(`called at ${Date.now()}`);\n  }\n\n  const [isReady, cancel, reset] = useTimeoutFn(fn, 5000);\n  const cancelButtonClick = useCallback(() => {\n    if (isReady() === false) {\n      cancel();\n      setState(`cancelled`);\n    } else {\n      reset();\n      setState('Not called yet');\n    }\n  }, []);\n\n  const readyState = isReady();\n\n  return (\n    <div>\n      <div>{readyState !== null ? 'Function will be called in 5 seconds' : 'Timer cancelled'}</div>\n      <button onClick={cancelButtonClick}>\n        {' '}\n        {readyState === false ? 'cancel' : 'restart'} timeout\n      </button>\n      <br />\n      <div>\n        Function state: {readyState === false ? 'Pending' : readyState ? 'Called' : 'Cancelled'}\n      </div>\n      <div>{state}</div>\n    </div>\n  );\n};\n\nstoriesOf('Animation/useTimeoutFn', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useTimeoutFn.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useTitle.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useTitle } from '../src';\nimport NewTabStory from './util/NewTabStory';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  useTitle('Hello world!');\n\n  return <NewTabStory>Title should be \"Hello world!\"</NewTabStory>;\n};\n\nstoriesOf('Side effects/useTitle', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useTitle.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useToggle.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useToggle } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [on, toggle] = useToggle(true);\n\n  return (\n    <div>\n      <div>{on ? 'ON' : 'OFF'}</div>\n      <button onClick={toggle}>Toggle</button>\n      <button onClick={() => toggle(true)}>set ON</button>\n      <button onClick={() => toggle(false)}>set OFF</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useToggle', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useToggle.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useTween.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useTween } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const t = useTween();\n\n  return <div>Tween: {t}</div>;\n};\n\nstoriesOf('Animation/useTween', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useTween.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useUnmount.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useUnmount } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  useUnmount(() => alert('UNMOUNTED'));\n\n  return (\n    <div>\n      <code>useUnmount()</code> hook can be used to perform side-effects when component unmounts.\n      This component will alert you when it is un-mounted.\n    </div>\n  );\n};\n\nstoriesOf('Lifecycle/useUnmount', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useUnmount.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useUpdate.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useUpdate } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const update = useUpdate();\n  return (\n    <>\n      <div>Time: {Date.now()}</div>\n      <button onClick={update}>Update</button>\n    </>\n  );\n};\n\nstoriesOf('Animation/useUpdate', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useUpdate.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useUpdateEffect.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useUpdateEffect } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [count, setCount] = React.useState(0);\n  const [didUpdate, setDidUpdate] = React.useState(false);\n\n  useUpdateEffect(() => {\n    setDidUpdate(true);\n  }, [count]);\n\n  return (\n    <div>\n      <button onClick={() => setCount((currentCount) => currentCount + 1)}>Count: {count}</button>\n      <p>Updated: {didUpdate}</p>\n    </div>\n  );\n};\n\nstoriesOf('Lifecycle/useUpdateEffect', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useUpdateEffect.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useUpsert.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useUpsert } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\ninterface DemoType {\n  id: string;\n  text: string;\n}\n\nconst initialItems: DemoType[] = [\n  { id: '1', text: 'Sample' },\n  { id: '2', text: '' },\n];\n\nconst Demo = () => {\n  const comparisonFunction = (a: DemoType, b: DemoType) => {\n    return a.id === b.id;\n  };\n  const [list, { set, upsert, remove }] = useUpsert(comparisonFunction, initialItems);\n\n  return (\n    <div style={{ display: 'inline-flex', flexDirection: 'column' }}>\n      {list.map((item: DemoType, index: number) => (\n        <div key={item.id}>\n          <input value={item.text} onChange={(e) => upsert({ ...item, text: e.target.value })} />\n          <button onClick={() => remove(index)}>Remove</button>\n        </div>\n      ))}\n      <button onClick={() => upsert({ id: (list.length + 1).toString(), text: '' })}>\n        Add item\n      </button>\n      <button onClick={() => set([])}>Reset</button>\n    </div>\n  );\n};\n\nstoriesOf('State/useUpsert', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useUpsert.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useVibrate.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useVibrate, useToggle } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [vibrating, toggleVibrating] = useToggle(false);\n\n  useVibrate(vibrating, [300, 100, 200, 100, 1000, 300]);\n\n  return (\n    <div>\n      <button onClick={toggleVibrating}>{vibrating ? 'Stop' : 'Vibrate'}</button>\n    </div>\n  );\n};\n\nstoriesOf('UI/useVibrate', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useVibrate.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useVideo.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useVideo } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const [video, state, controls, ref] = useVideo(\n    <video src=\"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4\" autoPlay={true} />\n  );\n\n  return (\n    <div>\n      {video}\n      <pre>{JSON.stringify(state, null, 2)}</pre>\n      <button onClick={controls.pause}>Pause</button>\n      <button onClick={controls.play}>Play</button>\n      <br />\n      <button onClick={controls.mute}>Mute</button>\n      <button onClick={controls.unmute}>Un-mute</button>\n      <br />\n      <button onClick={() => controls.volume(0.1)}>Volume: 10%</button>\n      <button onClick={() => controls.volume(0.5)}>Volume: 50%</button>\n      <button onClick={() => controls.volume(1)}>Volume: 100%</button>\n      <br />\n      <button onClick={() => controls.seek(state.time - 5)}>-5 sec</button>\n      <button onClick={() => controls.seek(state.time + 5)}>+5 sec</button>\n    </div>\n  );\n};\n\nstoriesOf('UI/useVideo', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useVideo.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useWindowScroll.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useWindowScroll } from '../src';\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const { x, y } = useWindowScroll();\n\n  return (\n    <div\n      style={{\n        width: '200vw',\n        height: '200vh',\n      }}>\n      <div\n        style={{\n          position: 'fixed',\n          left: 0,\n          right: 0,\n        }}>\n        <div>x: {x}</div>\n        <div>y: {y}</div>\n      </div>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useWindowScroll', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useWindowScroll.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/useWindowSize.story.tsx",
    "content": "import { storiesOf } from '@storybook/react';\nimport * as React from 'react';\nimport { useWindowSize } from '../src';\nimport { action } from '@storybook/addon-actions'; // Import addon-actions\nimport ShowDocs from './util/ShowDocs';\n\nconst Demo = () => {\n  const { width, height } = useWindowSize({\n    // Log the resize event to the Storybook actions panel\n    onChange: action('window resize'),\n  });\n\n  return (\n    <div>\n      <div>width: {width}</div>\n      <div>height: {height}</div>\n    </div>\n  );\n};\n\nstoriesOf('Sensors/useWindowSize', module)\n  .add('Docs', () => <ShowDocs md={require('../docs/useWindowSize.md')} />)\n  .add('Demo', () => <Demo />);\n"
  },
  {
    "path": "stories/util/CenterStory.tsx",
    "content": "import * as React from 'react';\n\nexport const CenterStory = ({ children }) => (\n  <div\n    style={{\n      display: 'flex',\n      justifyContent: 'center',\n      alignItems: 'center',\n      maxWidth: '400px',\n      margin: '40px auto',\n    }}>\n    <div style={{ width: '100%' }}>{children}</div>\n  </div>\n);\n"
  },
  {
    "path": "stories/util/ConsoleStory.tsx",
    "content": "import * as React from 'react';\n\nconst ConsoleStory = ({ message = 'Open the developer console to see logs' }) => <p>{message}</p>;\n\nexport default ConsoleStory;\n"
  },
  {
    "path": "stories/util/NewTabStory.tsx",
    "content": "import * as React from 'react';\n\nconst NewTabStory = ({ children }) => {\n  if (window.location === window.parent.location) {\n    return children;\n  }\n\n  return (\n    <p>\n      This story should be{' '}\n      <a href={window.location.href} target=\"_blank\" title=\"Open in new tab\" rel=\"noreferrer\">\n        opened in a new tab\n      </a>\n      .\n    </p>\n  );\n};\n\nexport default NewTabStory;\n"
  },
  {
    "path": "stories/util/ShowDocs.tsx",
    "content": "import * as React from 'react';\n\nconst h = React.createElement;\n\nconst ShowDocs = (props) => {\n  return h(\n    'div',\n    {},\n    h('div', {\n      style: {\n        padding: '0 20px',\n      },\n      dangerouslySetInnerHTML: {\n        __html: props.md.default,\n      },\n    }),\n    h('style', {\n      dangerouslySetInnerHTML: {\n        __html: `\n@import url(https://fonts.googleapis.com/css?family=Merriweather:300italic,300);\n\nh1, h1 code, h2, h2 code, h3, h3 code, h4, h4 code {\n  color: #333;\n}\n\nhtml {\n  font-size: 16px;\n  max-width: 700px;\n  margin: auto;\n}\n\nbody {\n  color: #444;\n  font-family: 'Merriweather', Georgia, serif;\n  max-width: 700px;\n  margin: auto;\n}\n\n/* === A bit of a gross hack so we can have bleeding divs/blockquotes. */\n\ndiv {\n  width: 100%;\n}\n\ndiv img {\n  width: 100%;\n}\n\nblockquote p {\n  font-size: 1.5rem;\n  font-style: italic;\n  margin: 1rem auto 1rem;\n  max-width: 48rem;\n}\n\nli {\n  margin-left: 2rem;\n}\n\n/* Counteract the specificity of the gross *:not() chain. */\nh1 {\n  padding: 1m 0 !important;\n}\n/*  === End gross hack */\n\np {\n  color: #555;\n  height: auto;\n  line-height: 1.45;\n}\n\npre, code {\n  font-family: Menlo, Monaco, \"Courier New\", monospace;\n  color: #42b983;\n}\n\npre, pre code {\n  color: #000;\n}\n\npre {\n  background-color: #fafafa;\n  font-size: .8rem;\n  overflow-x: scroll;\n  padding: 1.125em;\n}\n\na, a pre, a code,\na:visited {\n  color: #3498db;\n}\n\na:hover,\na:focus,\na:active {\n  color: #2980b9;\n}\n        `,\n      },\n    })\n  );\n};\n\nexport default ShowDocs;\n"
  },
  {
    "path": "tests/createBreakpoint.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport createBreakpoint from '../src/factory/createBreakpoint';\n\nconst useBreakpointA = createBreakpoint();\nconst useBreakpointB = createBreakpoint({ mobileM: 350, laptop: 1024, tablet: 768 });\n\nconst originalInnerWidth = window.innerWidth;\nconst changeInnerWidth = (value) =>\n  Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value });\nconst revert = () => changeInnerWidth(originalInnerWidth);\n\ndescribe('createBreakpoint', () => {\n  test('should use default', () => {\n    const { result } = renderHook(() => useBreakpointA());\n    act(() => {\n      changeInnerWidth(100);\n      window.dispatchEvent(new Event('resize'));\n    });\n    expect(result.current).toBe('tablet');\n\n    act(() => {\n      changeInnerWidth(200);\n      window.dispatchEvent(new Event('resize'));\n    });\n    expect(result.current).toBe('tablet');\n\n    act(() => {\n      changeInnerWidth(1100);\n      window.dispatchEvent(new Event('resize'));\n    });\n    expect(result.current).toBe('laptop');\n\n    act(() => {\n      changeInnerWidth(1500);\n      window.dispatchEvent(new Event('resize'));\n    });\n    expect(result.current).toBe('laptopL');\n\n    act(() => {\n      revert();\n    });\n  });\n\n  test('should use custom', () => {\n    const { result } = renderHook(() => useBreakpointB());\n    act(() => {\n      changeInnerWidth(100);\n      window.dispatchEvent(new Event('resize'));\n    });\n    expect(result.current).toBe('mobileM');\n\n    act(() => {\n      changeInnerWidth(200);\n      window.dispatchEvent(new Event('resize'));\n    });\n    expect(result.current).toBe('mobileM');\n\n    act(() => {\n      changeInnerWidth(800);\n      window.dispatchEvent(new Event('resize'));\n    });\n    expect(result.current).toBe('tablet');\n\n    act(() => {\n      changeInnerWidth(1100);\n      window.dispatchEvent(new Event('resize'));\n    });\n    expect(result.current).toBe('laptop');\n\n    act(() => {\n      revert();\n    });\n  });\n});\n"
  },
  {
    "path": "tests/createGlobalState.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport createGlobalState from '../src/factory/createGlobalState';\n\ndescribe('useGlobalState', () => {\n  it('should be defined', () => {\n    expect(createGlobalState).toBeDefined();\n  });\n\n  it('both components should be updated', () => {\n    const useGlobalValue = createGlobalState(0);\n    const { result: result1 } = renderHook(() => useGlobalValue());\n    const { result: result2 } = renderHook(() => useGlobalValue());\n    expect(result1.current[0]).toBe(0);\n    expect(result2.current[0]).toBe(0);\n    act(() => {\n      result1.current[1](1);\n    });\n    expect(result1.current[0]).toBe(1);\n    expect(result2.current[0]).toBe(1);\n  });\n\n  it('allows setting state with function and previous value', () => {\n    const useGlobalValue = createGlobalState(0);\n    const { result: result1 } = renderHook(() => useGlobalValue());\n    const { result: result2 } = renderHook(() => useGlobalValue());\n    expect(result1.current[0]).toBe(0);\n    expect(result2.current[0]).toBe(0);\n    act(() => {\n      result1.current[1]((value) => value + 1);\n    });\n    expect(result1.current[0]).toBe(1);\n    expect(result2.current[0]).toBe(1);\n  });\n\n  it('allows setting state with function and no previous value', () => {\n    const useGlobalValue = createGlobalState(0);\n    const { result: result1 } = renderHook(() => useGlobalValue());\n    const { result: result2 } = renderHook(() => useGlobalValue());\n    expect(result1.current[0]).toBe(0);\n    expect(result2.current[0]).toBe(0);\n    act(() => {\n      result1.current[1](() => 1);\n    });\n    expect(result1.current[0]).toBe(1);\n    expect(result2.current[0]).toBe(1);\n  });\n\n  it('initializes and updates with undefined', () => {\n    const useGlobalValue = createGlobalState<number>();\n    const { result: result1 } = renderHook(() => useGlobalValue());\n    const { result: result2 } = renderHook(() => useGlobalValue());\n    expect(result1.current[0]).toBe(undefined);\n    expect(result2.current[0]).toBe(undefined);\n    act(() => {\n      // this is the only case where types fail, it should guard the number\n      result1.current[1]((value) => value);\n    });\n    expect(result1.current[0]).toBe(undefined);\n    expect(result2.current[0]).toBe(undefined);\n  });\n\n  it('initializes with undefined and updates with different type', () => {\n    const useGlobalValue = createGlobalState();\n    const { result: result1 } = renderHook(() => useGlobalValue());\n    const { result: result2 } = renderHook(() => useGlobalValue());\n    expect(result1.current[0]).toBe(undefined);\n    expect(result2.current[0]).toBe(undefined);\n    act(() => {\n      // @ts-expect-error this case it checks correctly, hence the comment\n      result1.current[1]((value) => 1);\n    });\n  });\n\n  it('initializes with function', () => {\n    const useGlobalValue = createGlobalState(() => 0);\n    const { result: result1 } = renderHook(() => useGlobalValue());\n    const { result: result2 } = renderHook(() => useGlobalValue());\n    expect(result1.current[0]).toBe(0);\n    expect(result2.current[0]).toBe(0);\n    act(() => {\n      result1.current[1](1);\n    });\n    expect(result1.current[0]).toBe(1);\n    expect(result2.current[0]).toBe(1);\n  });\n});\n"
  },
  {
    "path": "tests/createMemo.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport createMemo from '../src/factory/createMemo';\n\nconst getDouble = jest.fn((n: number): number => n * 2);\n\nit('should init memo hook', () => {\n  const useMemoGetDouble = createMemo(getDouble);\n\n  expect(useMemoGetDouble).toBeInstanceOf(Function);\n});\n\ndescribe('when using created memo hook', () => {\n  let useMemoGetDouble;\n\n  beforeEach(() => {\n    useMemoGetDouble = createMemo(getDouble);\n  });\n\n  it.each([[1], [3], [5]])(\n    'should return same result as original function for argument %d',\n    (val: number) => {\n      const { result } = renderHook(() => useMemoGetDouble(val));\n      expect(result.current).toBe(getDouble(val));\n    }\n  );\n\n  it('should NOT call original function for same arguments', () => {\n    let initialValue = 5;\n    expect(getDouble).not.toHaveBeenCalled();\n\n    // it's called first time calculating for argument 5\n    const { rerender } = renderHook(() => useMemoGetDouble(initialValue));\n    expect(getDouble).toHaveBeenCalled();\n\n    getDouble.mockClear();\n\n    // it's NOT called second time calculating for argument 5\n    rerender();\n    expect(getDouble).not.toHaveBeenCalled();\n\n    getDouble.mockClear();\n\n    // it's called again calculating for different argument\n    initialValue = 7;\n    rerender();\n    expect(getDouble).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "tests/createReducer.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport logger from 'redux-logger';\nimport thunk from 'redux-thunk';\nimport createReducer from '../src/factory/createReducer';\n\nit('should init reducer hook function', () => {\n  const useSomeReducer = createReducer();\n  expect(useSomeReducer).toBeInstanceOf(Function);\n});\n\n/**\n * This test suite implements the special demo in storybook that creates a\n * reducer with thunk and logger for using a simple counter\n */\ndescribe('when using created reducer hook', () => {\n  const initialCount = 1;\n  let originalLog;\n  let originalGroup;\n  const mockLog = jest.fn();\n  const mockGroup = jest.fn();\n\n  function reducer(state, action) {\n    switch (action.type) {\n      case 'increment':\n        return { count: state.count + 1 };\n      case 'decrement':\n        return { count: state.count - 1 };\n      case 'reset':\n        return { count: action.payload };\n      default:\n        throw new Error();\n    }\n  }\n\n  // Action creator to increment count, wait a second and then reset\n  const addAndReset = () => {\n    return (dispatch) => {\n      dispatch({ type: 'increment' });\n\n      setTimeout(() => {\n        dispatch({ type: 'reset', payload: initialCount });\n      }, 1000);\n    };\n  };\n\n  const setUp = () => {\n    const useThunkReducer = createReducer(thunk, logger);\n    return renderHook(() => useThunkReducer(reducer, { count: initialCount }));\n  };\n\n  beforeAll(() => {\n    originalLog = console.log;\n    originalGroup = console.group;\n    console.log = mockLog;\n    console.group = mockGroup;\n  });\n\n  beforeEach(() => {\n    jest.useFakeTimers();\n  });\n\n  afterAll(() => {\n    console.log = originalLog;\n    console.group = originalGroup;\n  });\n\n  it('should init state and dispatcher', () => {\n    const { result } = setUp();\n    const [state, dispatch] = result.current;\n\n    expect(state).toEqual({ count: 1 });\n    expect(dispatch).toBeInstanceOf(Function);\n  });\n\n  it.each`\n    actionType     | expectedCount | payload\n    ${'increment'} | ${2}          | ${undefined}\n    ${'decrement'} | ${0}          | ${undefined}\n    ${'reset'}     | ${1}          | ${1}\n  `('should handle \"$actionType\" action', ({ actionType, expectedCount, payload }) => {\n    const { result } = setUp();\n    const [, dispatch] = result.current;\n    expect(mockLog).not.toHaveBeenCalled();\n\n    act(() => {\n      dispatch({ type: actionType, payload });\n    });\n\n    expect(result.current[0]).toEqual({ count: expectedCount });\n    expect(mockLog).toHaveBeenCalled();\n  });\n\n  it('should handle async action with several middlewares', () => {\n    const { result } = setUp();\n    const [, dispatch] = result.current;\n    expect(mockLog).not.toHaveBeenCalled();\n\n    act(() => {\n      dispatch(addAndReset());\n    });\n\n    expect(result.current[0]).toEqual({ count: 2 });\n    expect(mockLog).toHaveBeenCalled();\n\n    // fast-forward until all timers have been executed\n    act(() => {\n      jest.runAllTimers();\n    });\n\n    expect(result.current[0]).toEqual({ count: 1 });\n  });\n});\n"
  },
  {
    "path": "tests/createReducerContext.test.tsx",
    "content": "import React from 'react';\nimport { render, fireEvent } from '@testing-library/react';\nimport { act, renderHook } from '@testing-library/react-hooks';\nimport createReducerContext from '../src/factory/createReducerContext';\n\ntype Action = 'increment' | 'decrement';\n\nconst reducer = (state: number, action: Action) => {\n  switch (action) {\n    case 'increment':\n      return state + 1;\n    case 'decrement':\n      return state - 1;\n    default:\n      throw new Error();\n  }\n};\n\nit('should create a hook and a provider', () => {\n  const [useSharedNumber, SharedNumberProvider] = createReducerContext(reducer, 0);\n  expect(useSharedNumber).toBeInstanceOf(Function);\n  expect(SharedNumberProvider).toBeInstanceOf(Function);\n});\n\ndescribe('when using created hook', () => {\n  it('should throw out of a provider', () => {\n    const [useSharedNumber] = createReducerContext(reducer, 0);\n    const { result } = renderHook(() => useSharedNumber());\n    expect(result.error).toEqual(\n      new Error('useReducerContext must be used inside a ReducerProvider.')\n    );\n  });\n\n  const setUp = () => {\n    const [useSharedNumber, SharedNumberProvider] = createReducerContext(reducer, 0);\n    const wrapper = ({ children }: { children?: React.ReactNode }) => (\n      <SharedNumberProvider>{children}</SharedNumberProvider>\n    );\n    return renderHook(() => useSharedNumber(), { wrapper });\n  };\n\n  it('should init state and updater', () => {\n    const { result } = setUp();\n    const [sharedNumber, updateSharedNumber] = result.current;\n\n    expect(sharedNumber).toEqual(0);\n    expect(updateSharedNumber).toBeInstanceOf(Function);\n  });\n\n  it('should update the state', () => {\n    const { result } = setUp();\n    const [, updateSharedNumber] = result.current;\n\n    act(() => updateSharedNumber('increment'));\n\n    const [sharedNumber] = result.current;\n\n    expect(sharedNumber).toEqual(1);\n  });\n});\n\ndescribe('when using among multiple components', () => {\n  const [useSharedNumber, SharedNumberProvider] = createReducerContext(reducer, 0);\n\n  const DisplayComponent = () => {\n    const [sharedNumber] = useSharedNumber();\n    return <p>{sharedNumber}</p>;\n  };\n\n  const UpdateComponent = () => {\n    const [, updateSharedNumber] = useSharedNumber();\n    return (\n      <button type=\"button\" onClick={() => updateSharedNumber('increment')}>\n        INCREMENT\n      </button>\n    );\n  };\n\n  it('should be in sync when under the same provider', () => {\n    const { baseElement, getByText } = render(\n      <SharedNumberProvider>\n        <DisplayComponent />\n        <DisplayComponent />\n        <UpdateComponent />\n      </SharedNumberProvider>\n    );\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>0</p><p>0</p><button type=\"button\">INCREMENT</button></div>'\n    );\n\n    fireEvent.click(getByText('INCREMENT'));\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>1</p><p>1</p><button type=\"button\">INCREMENT</button></div>'\n    );\n  });\n\n  it('should be in update independently when under different providers', () => {\n    const { baseElement, getByText } = render(\n      <>\n        <SharedNumberProvider>\n          <DisplayComponent />\n        </SharedNumberProvider>\n        <SharedNumberProvider>\n          <DisplayComponent />\n          <UpdateComponent />\n        </SharedNumberProvider>\n      </>\n    );\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>0</p><p>0</p><button type=\"button\">INCREMENT</button></div>'\n    );\n\n    fireEvent.click(getByText('INCREMENT'));\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>0</p><p>1</p><button type=\"button\">INCREMENT</button></div>'\n    );\n  });\n\n  it('should not update component that do not use the state context', () => {\n    let renderCount = 0;\n    const StaticComponent = () => {\n      renderCount++;\n      return <p>static</p>;\n    };\n\n    const { baseElement, getByText } = render(\n      <>\n        <SharedNumberProvider>\n          <StaticComponent />\n          <DisplayComponent />\n          <UpdateComponent />\n        </SharedNumberProvider>\n      </>\n    );\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>static</p><p>0</p><button type=\"button\">INCREMENT</button></div>'\n    );\n\n    fireEvent.click(getByText('INCREMENT'));\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>static</p><p>1</p><button type=\"button\">INCREMENT</button></div>'\n    );\n\n    expect(renderCount).toBe(1);\n  });\n\n  it('should override initialValue', () => {\n    const { baseElement } = render(\n      <>\n        <SharedNumberProvider>\n          <DisplayComponent />\n        </SharedNumberProvider>\n        <SharedNumberProvider initialState={15}>\n          <DisplayComponent />\n        </SharedNumberProvider>\n      </>\n    );\n\n    expect(baseElement.innerHTML).toBe('<div><p>0</p><p>15</p></div>');\n  });\n});\n"
  },
  {
    "path": "tests/createStateContext.test.tsx",
    "content": "import React from 'react';\nimport { render, fireEvent } from '@testing-library/react';\nimport { act, renderHook } from '@testing-library/react-hooks';\nimport createStateContext from '../src/factory/createStateContext';\n\nit('should create a hook and a provider', () => {\n  const [useSharedNumber, SharedNumberProvider] = createStateContext(0);\n  expect(useSharedNumber).toBeInstanceOf(Function);\n  expect(SharedNumberProvider).toBeInstanceOf(Function);\n});\n\ndescribe('when using created hook', () => {\n  it('should throw out of a provider', () => {\n    const [useSharedText] = createStateContext('init');\n    const { result } = renderHook(() => useSharedText());\n    expect(result.error).toEqual(new Error('useStateContext must be used inside a StateProvider.'));\n  });\n\n  const setUp = () => {\n    const [useSharedText, SharedTextProvider] = createStateContext('init');\n    const wrapper = ({ children }: { children?: React.ReactNode }) => (\n      <SharedTextProvider>{children}</SharedTextProvider>\n    );\n    return renderHook(() => useSharedText(), { wrapper });\n  };\n\n  it('should init state and updater', () => {\n    const { result } = setUp();\n    const [sharedText, setSharedText] = result.current;\n\n    expect(sharedText).toEqual('init');\n    expect(setSharedText).toBeInstanceOf(Function);\n  });\n\n  it('should update the state', () => {\n    const { result } = setUp();\n    const [, setSharedText] = result.current;\n\n    act(() => setSharedText('changed'));\n\n    const [sharedText] = result.current;\n\n    expect(sharedText).toEqual('changed');\n  });\n});\n\ndescribe('when using among multiple components', () => {\n  const [useSharedText, SharedTextProvider] = createStateContext('init');\n\n  const DisplayComponent = () => {\n    const [sharedText] = useSharedText();\n    return <p>{sharedText}</p>;\n  };\n\n  const UpdateComponent = () => {\n    const [, setSharedText] = useSharedText();\n    return (\n      <button type=\"button\" onClick={() => setSharedText('changed')}>\n        UPDATE\n      </button>\n    );\n  };\n\n  it('should be in sync when under the same provider', () => {\n    const { baseElement, getByText } = render(\n      <SharedTextProvider>\n        <DisplayComponent />\n        <DisplayComponent />\n        <UpdateComponent />\n      </SharedTextProvider>\n    );\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>init</p><p>init</p><button type=\"button\">UPDATE</button></div>'\n    );\n\n    fireEvent.click(getByText('UPDATE'));\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>changed</p><p>changed</p><button type=\"button\">UPDATE</button></div>'\n    );\n  });\n\n  it('should be in update independently when under different providers', () => {\n    const { baseElement, getByText } = render(\n      <>\n        <SharedTextProvider>\n          <DisplayComponent />\n        </SharedTextProvider>\n        <SharedTextProvider>\n          <DisplayComponent />\n          <UpdateComponent />\n        </SharedTextProvider>\n      </>\n    );\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>init</p><p>init</p><button type=\"button\">UPDATE</button></div>'\n    );\n\n    fireEvent.click(getByText('UPDATE'));\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>init</p><p>changed</p><button type=\"button\">UPDATE</button></div>'\n    );\n  });\n\n  it('should not update component that do not use the state context', () => {\n    let renderCount = 0;\n    const StaticComponent = () => {\n      renderCount++;\n      return <p>static</p>;\n    };\n\n    const { baseElement, getByText } = render(\n      <>\n        <SharedTextProvider>\n          <StaticComponent />\n          <DisplayComponent />\n          <UpdateComponent />\n        </SharedTextProvider>\n      </>\n    );\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>static</p><p>init</p><button type=\"button\">UPDATE</button></div>'\n    );\n\n    fireEvent.click(getByText('UPDATE'));\n\n    expect(baseElement.innerHTML).toBe(\n      '<div><p>static</p><p>changed</p><button type=\"button\">UPDATE</button></div>'\n    );\n\n    expect(renderCount).toBe(1);\n  });\n\n  it('should override initialValue', () => {\n    const { baseElement } = render(\n      <>\n        <SharedTextProvider>\n          <DisplayComponent />\n        </SharedTextProvider>\n        <SharedTextProvider initialValue={'other'}>\n          <DisplayComponent />\n        </SharedTextProvider>\n      </>\n    );\n\n    expect(baseElement.innerHTML).toBe('<div><p>init</p><p>other</p></div>');\n  });\n});\n"
  },
  {
    "path": "tests/misc/hookState.test.ts",
    "content": "import { resolveHookState } from '../../src/misc/hookState';\n\ndescribe('resolveHookState', () => {\n  it('should defined', () => {\n    expect(resolveHookState).toBeDefined();\n  });\n\n  it(`should return value as is if it's not a function`, () => {\n    expect(resolveHookState(1)).toBe(1);\n    expect(resolveHookState('HI!')).toBe('HI!');\n    expect(resolveHookState(undefined)).toBe(undefined);\n  });\n\n  it('should call passed function', () => {\n    const spy = jest.fn();\n    resolveHookState(spy);\n    expect(spy).toHaveBeenCalled();\n  });\n\n  it('should pass 2nd parameter to function if it awaited', () => {\n    const spy = jest.fn((n: number) => n);\n    resolveHookState(spy, 123);\n    expect(spy).toHaveBeenCalled();\n    expect(spy.mock.calls[0][0]).toBe(123);\n  });\n\n  it('should not pass 2nd parameter to function if it not awaited', () => {\n    const spy = jest.fn(() => {});\n    /* @ts-expect-error */\n    resolveHookState(spy, 123);\n    expect(spy).toHaveBeenCalled();\n    expect(spy.mock.calls[0].length).toBe(0);\n  });\n});\n"
  },
  {
    "path": "tests/setupTests.ts",
    "content": "import 'jest-localstorage-mock';\nimport { isBrowser } from '../src/misc/util';\n\nif (isBrowser) {\n  (window as any).ResizeObserver = class ResizeObserver {\n    observe() {}\n\n    disconnect() {}\n  };\n}\n"
  },
  {
    "path": "tests/useAsync.test.tsx",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useCallback } from 'react';\nimport useAsync from '../src/useAsync';\n\ndescribe('useAsync', () => {\n  it('should be defined', () => {\n    expect(useAsync).toBeDefined();\n  });\n\n  describe('a success', () => {\n    let hook;\n    let callCount = 0;\n\n    const resolver = async () => {\n      return new Promise((resolve) => {\n        callCount++;\n\n        const wait = setTimeout(() => {\n          clearTimeout(wait);\n          resolve('yay');\n        }, 0);\n      });\n    };\n\n    beforeEach(() => {\n      callCount = 0;\n      hook = renderHook(({ fn }) => useAsync(fn, [fn]), {\n        initialProps: {\n          fn: resolver,\n        },\n      });\n    });\n\n    it('initially starts loading', async () => {\n      expect(hook.result.current.loading).toEqual(true);\n      await hook.waitForNextUpdate();\n    });\n\n    it('resolves', async () => {\n      expect.assertions(4);\n\n      hook.rerender({ fn: resolver });\n      await hook.waitForNextUpdate();\n\n      expect(callCount).toEqual(1);\n      expect(hook.result.current.loading).toBeFalsy();\n      expect(hook.result.current.value).toEqual('yay');\n      expect(hook.result.current.error).toEqual(undefined);\n    });\n  });\n\n  describe('an error', () => {\n    let hook;\n    let callCount = 0;\n\n    const rejection = async () => {\n      return new Promise((_, reject) => {\n        callCount++;\n\n        const wait = setTimeout(() => {\n          clearTimeout(wait);\n          reject('yay');\n        }, 0);\n      });\n    };\n\n    beforeEach(() => {\n      callCount = 0;\n      hook = renderHook(({ fn }) => useAsync(fn, [fn]), {\n        initialProps: {\n          fn: rejection,\n        },\n      });\n    });\n\n    it('initially starts loading', async () => {\n      expect(hook.result.current.loading).toBeTruthy();\n      await hook.waitForNextUpdate();\n    });\n\n    it('resolves', async () => {\n      expect.assertions(4);\n\n      hook.rerender({ fn: rejection });\n      await hook.waitForNextUpdate();\n\n      expect(callCount).toEqual(1);\n      expect(hook.result.current.loading).toBeFalsy();\n      expect(hook.result.current.error).toEqual('yay');\n      expect(hook.result.current.value).toEqual(undefined);\n    });\n  });\n\n  describe('re-evaluates when dependencies change', () => {\n    describe('the fn is a dependency', () => {\n      let hook;\n      let callCount = 0;\n\n      const initialFn = async () => {\n        callCount++;\n        return 'value';\n      };\n\n      const differentFn = async () => {\n        callCount++;\n        return 'new value';\n      };\n\n      beforeEach((done) => {\n        callCount = 0;\n\n        hook = renderHook(({ fn }) => useAsync(fn, [fn]), {\n          initialProps: { fn: initialFn },\n        });\n\n        hook.waitForNextUpdate().then(done);\n      });\n\n      it('renders the first value', () => {\n        expect(hook.result.current.value).toEqual('value');\n      });\n\n      it('renders a different value when deps change', async () => {\n        expect.assertions(3);\n\n        expect(callCount).toEqual(1);\n\n        hook.rerender({ fn: differentFn }); // change the fn to initiate new request\n        await hook.waitForNextUpdate();\n\n        expect(callCount).toEqual(2);\n        expect(hook.result.current.value).toEqual('new value');\n      });\n    });\n\n    describe('the additional dependencies list changes', () => {\n      let callCount = 0;\n      let hook;\n\n      const staticFunction = async (counter) => {\n        callCount++;\n        return `counter is ${counter} and callCount is ${callCount}`;\n      };\n\n      beforeEach((done) => {\n        callCount = 0;\n        hook = renderHook(\n          ({ fn, counter }) => {\n            const callback = useCallback(() => fn(counter), [counter]);\n            return useAsync<any>(callback, [callback]);\n          },\n          {\n            initialProps: {\n              counter: 0,\n              fn: staticFunction,\n            },\n          }\n        );\n\n        hook.waitForNextUpdate().then(done);\n      });\n\n      it('initial renders the first passed pargs', () => {\n        expect(hook.result.current.value).toEqual('counter is 0 and callCount is 1');\n      });\n\n      it('renders a different value when deps change', async () => {\n        expect.assertions(1);\n\n        hook.rerender({ fn: staticFunction, counter: 1 });\n        await hook.waitForNextUpdate();\n\n        expect(hook.result.current.value).toEqual('counter is 1 and callCount is 2');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/useAsyncFn.test.tsx",
    "content": "// NOTE: most behavior that useAsyncFn provides\n//       is covered be the useAsync tests.\n//\n// The main difference is that useAsyncFn\n// does not automatically invoke the function\n// and it can take arguments.\n\nimport { act, renderHook } from '@testing-library/react-hooks';\nimport useAsyncFn, { AsyncState } from '../src/useAsyncFn';\n\ntype AdderFn = (a?: number, b?: number) => Promise<number>;\n\ndescribe('useAsyncFn', () => {\n  it('should be defined', () => {\n    expect(useAsyncFn).toBeDefined();\n  });\n\n  describe('the callback can be awaited and return the value', () => {\n    let hook;\n    const adder: AdderFn = async (a?: number, b?: number): Promise<number> => {\n      return (a || 0) + (b || 0);\n    };\n\n    beforeEach(() => {\n      // NOTE: renderHook isn't good at inferring array types\n      hook = renderHook<{ fn: AdderFn }, [AsyncState<number>, AdderFn]>(\n        ({ fn }) => useAsyncFn(fn),\n        {\n          initialProps: { fn: adder },\n        }\n      );\n    });\n\n    it('awaits the result', async () => {\n      expect.assertions(3);\n\n      const [, callback] = hook.result.current;\n      let result;\n\n      await act(async () => {\n        result = await callback(5, 7);\n      });\n\n      expect(result).toEqual(12);\n\n      const [state] = hook.result.current;\n\n      expect(state.value).toEqual(12);\n      expect(result).toEqual(state.value);\n    });\n  });\n\n  describe('args can be passed to the function', () => {\n    let hook;\n    let callCount = 0;\n    const adder = async (a?: number, b?: number): Promise<number> => {\n      callCount++;\n      return (a || 0) + (b || 0);\n    };\n\n    beforeEach(() => {\n      // NOTE: renderHook isn't good at inferring array types\n      hook = renderHook<{ fn: AdderFn }, [AsyncState<number>, AdderFn]>(\n        ({ fn }) => useAsyncFn(fn),\n        {\n          initialProps: {\n            fn: adder,\n          },\n        }\n      );\n    });\n\n    it('initially does not have a value', () => {\n      const [state] = hook.result.current;\n\n      expect(state.value).toEqual(undefined);\n      expect(state.loading).toEqual(false);\n      expect(state.error).toEqual(undefined);\n      expect(callCount).toEqual(0);\n    });\n\n    describe('when invoked', () => {\n      it('resolves a value derived from args', async () => {\n        expect.assertions(4);\n\n        const [, callback] = hook.result.current;\n\n        act(() => {\n          callback(2, 7);\n        });\n        hook.rerender({ fn: adder });\n        await hook.waitForNextUpdate();\n\n        const [state] = hook.result.current;\n\n        expect(callCount).toEqual(1);\n        expect(state.loading).toEqual(false);\n        expect(state.error).toEqual(undefined);\n        expect(state.value).toEqual(9);\n      });\n    });\n  });\n\n  it('should only consider last call and discard previous ones', async () => {\n    const queuedPromises: { id: number; resolve: () => void }[] = [];\n    const delayedFunction1 = () => {\n      return new Promise<number>((resolve) =>\n        queuedPromises.push({ id: 1, resolve: () => resolve(1) })\n      );\n    };\n    const delayedFunction2 = () => {\n      return new Promise<number>((resolve) =>\n        queuedPromises.push({ id: 2, resolve: () => resolve(2) })\n      );\n    };\n\n    const hook = renderHook<\n      { fn: () => Promise<number> },\n      [AsyncState<number>, () => Promise<number>]\n    >(({ fn }) => useAsyncFn(fn, [fn]), {\n      initialProps: { fn: delayedFunction1 },\n    });\n    act(() => {\n      hook.result.current[1](); // invoke 1st callback\n    });\n\n    hook.rerender({ fn: delayedFunction2 });\n    act(() => {\n      hook.result.current[1](); // invoke 2nd callback\n    });\n\n    act(() => {\n      queuedPromises[1].resolve();\n      queuedPromises[0].resolve();\n    });\n    await hook.waitForNextUpdate();\n    expect(hook.result.current[0]).toEqual({ loading: false, value: 2 });\n  });\n\n  it('should keeping value of initialState when loading', async () => {\n    const fetch = async () => 'new state';\n    const initialState = { loading: false, value: 'init state' };\n\n    const hook = renderHook<\n      { fn: () => Promise<string> },\n      [AsyncState<string>, () => Promise<string>]\n    >(({ fn }) => useAsyncFn(fn, [fn], initialState), {\n      initialProps: { fn: fetch },\n    });\n\n    const [state, callback] = hook.result.current;\n    expect(state.loading).toBe(false);\n    expect(state.value).toBe('init state');\n\n    act(() => {\n      callback();\n    });\n\n    expect(hook.result.current[0].loading).toBe(true);\n    expect(hook.result.current[0].value).toBe('init state');\n\n    await hook.waitForNextUpdate();\n    expect(hook.result.current[0].loading).toBe(false);\n    expect(hook.result.current[0].value).toBe('new state');\n  });\n});\n"
  },
  {
    "path": "tests/useAudio.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport useAudio from '../src/useAudio';\nconst setUp = (\n  src: string = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3',\n  autoPlay: boolean = true\n) => renderHook(() => useAudio({ src, autoPlay }));\n\nit('should init audio and utils', () => {\n  global.console.error = jest.fn();\n\n  const MOCK_AUDIO_SRC = 'MOCK_AUDIO_SRC';\n  const MOCK_AUTO_PLAY_STATE = true;\n  const { result } = setUp(MOCK_AUDIO_SRC, MOCK_AUTO_PLAY_STATE);\n  const [audio, state, controls, ref] = result.current;\n  // if not production mode, it will show the error message, cause audio do not render\n  expect(console.error).toHaveBeenCalledTimes(1);\n\n  // Test the audio comp\n  expect(audio.type).toBe('audio');\n  expect(audio.props.src).toBe(MOCK_AUDIO_SRC);\n  expect(audio.props.autoPlay).toBe(MOCK_AUTO_PLAY_STATE);\n\n  // Test state value\n  expect(state.time).toBe(0);\n  expect(state.paused).toBe(true);\n  expect(state.playing).toBe(false);\n  expect(state.muted).toBe(false);\n  expect(state.volume).toBe(1);\n\n  // Test controls\n  ref.current = document.createElement('audio');\n  // Mock ref current for controls testing\n\n  expect(ref.current.muted).toBe(false);\n  controls.mute();\n  expect(ref.current.muted).toBe(true);\n  controls.unmute();\n  expect(ref.current.muted).toBe(false);\n\n  expect(ref.current.volume).toBe(1);\n  controls.volume(0.5);\n  expect(ref.current.volume).toBe(0.5);\n});\n"
  },
  {
    "path": "tests/useBoolean.test.ts",
    "content": "import useBoolean from '../src/useBoolean';\nimport useToggle from '../src/useToggle';\n\nit('should be an alias for useToggle ', () => {\n  expect(useBoolean).toBe(useToggle);\n});\n"
  },
  {
    "path": "tests/useCookie.test.tsx",
    "content": "import { renderHook, act } from '@testing-library/react-hooks';\nimport Cookies from 'js-cookie';\nimport { useCookie } from '../src';\n\nconst setup = (cookieName: string) => renderHook(() => useCookie(cookieName));\n\nit('should have initial value of null if no cookie exists', () => {\n  const { result } = setup('some-cookie');\n\n  expect(result.current[0]).toBeNull();\n});\n\nit('should have initial value of the cookie if it exists', () => {\n  const cookieName = 'some-cookie';\n  const value = 'some-value';\n  Cookies.set(cookieName, value);\n\n  const { result } = setup(cookieName);\n\n  expect(result.current[0]).toBe(value);\n\n  // cleanup\n  Cookies.remove(cookieName);\n});\n\nit('should update the cookie on call to updateCookie', () => {\n  const spy = jest.spyOn(Cookies, 'set');\n\n  const cookieName = 'some-cookie';\n  const { result } = setup(cookieName);\n\n  const newValue = 'some-new-value';\n  act(() => {\n    result.current[1](newValue);\n  });\n\n  expect(result.current[0]).toBe(newValue);\n  expect(spy).toHaveBeenCalledTimes(1);\n  expect(spy).toHaveBeenCalledWith(cookieName, newValue, undefined);\n\n  // cleanup\n  spy.mockRestore();\n  Cookies.remove(cookieName);\n});\n\nit('should delete the cookie on call to deleteCookie', () => {\n  const cookieName = 'some-cookie';\n  const value = 'some-value';\n  Cookies.set(cookieName, value);\n\n  const spy = jest.spyOn(Cookies, 'remove');\n\n  const { result } = setup(cookieName);\n\n  expect(result.current[0]).toBe(value);\n\n  act(() => {\n    result.current[2]();\n  });\n\n  expect(result.current[0]).toBeNull();\n  expect(spy).toHaveBeenCalledTimes(1);\n  expect(spy).toHaveBeenLastCalledWith(cookieName);\n\n  // cleanup\n  spy.mockRestore();\n  Cookies.remove(cookieName);\n});\n"
  },
  {
    "path": "tests/useCopyToClipboard.test.ts",
    "content": "import writeText from 'copy-to-clipboard';\nimport { act, renderHook } from '@testing-library/react-hooks';\nimport { useCopyToClipboard } from '../src';\n\nconst valueToRaiseMockException = 'fake input causing exception in copy to clipboard';\njest.mock('copy-to-clipboard', () =>\n  jest.fn().mockImplementation((input) => {\n    if (input === valueToRaiseMockException) {\n      throw new Error(input);\n    }\n    return true;\n  })\n);\n\ndescribe('useCopyToClipboard', () => {\n  let hook;\n  let consoleErrorSpy = jest.spyOn(global.console, 'error').mockImplementation(() => {});\n\n  beforeEach(() => {\n    hook = renderHook(() => useCopyToClipboard());\n  });\n\n  afterAll(() => {\n    consoleErrorSpy.mockRestore();\n    jest.unmock('copy-to-clipboard');\n  });\n\n  it('should be defined ', () => {\n    expect(useCopyToClipboard).toBeDefined();\n  });\n\n  it('should pass a given value to copy to clipboard and set state', () => {\n    const testValue = 'test';\n    let [state, copyToClipboard] = hook.result.current;\n    act(() => copyToClipboard(testValue));\n    [state, copyToClipboard] = hook.result.current;\n\n    expect(writeText).toBeCalled();\n    expect(state.value).toBe(testValue);\n    expect(state.noUserInteraction).toBe(true);\n    expect(state.error).not.toBeDefined();\n  });\n\n  it('should not call writeText if passed an invalid input and set state', () => {\n    let testValue = {}; // invalid value\n    let [state, copyToClipboard] = hook.result.current;\n    act(() => copyToClipboard(testValue));\n    [state, copyToClipboard] = hook.result.current;\n\n    expect(writeText).not.toBeCalled();\n    expect(state.value).toBe(testValue);\n    expect(state.noUserInteraction).toBe(true);\n    expect(state.error).toBeDefined();\n\n    testValue = ''; // empty string is also invalid\n    act(() => copyToClipboard(testValue));\n    [state, copyToClipboard] = hook.result.current;\n\n    expect(writeText).not.toBeCalled();\n    expect(state.value).toBe(testValue);\n    expect(state.noUserInteraction).toBe(true);\n    expect(state.error).toBeDefined();\n  });\n\n  it('should catch exception thrown by copy-to-clipboard and set state', () => {\n    let [state, copyToClipboard] = hook.result.current;\n    act(() => copyToClipboard(valueToRaiseMockException));\n    [state, copyToClipboard] = hook.result.current;\n\n    expect(writeText).toBeCalledWith(valueToRaiseMockException);\n    expect(state.value).toBe(valueToRaiseMockException);\n    expect(state.noUserInteraction).not.toBeDefined();\n    expect(state.error).toStrictEqual(new Error(valueToRaiseMockException));\n  });\n\n  it('should return initial state while unmounted', () => {\n    hook.unmount();\n    const [state, copyToClipboard] = hook.result.current;\n\n    act(() => copyToClipboard('value'));\n    expect(state.value).not.toBeDefined();\n    expect(state.error).not.toBeDefined();\n    expect(state.noUserInteraction).toBe(true);\n  });\n\n  it('should console error if in dev environment', () => {\n    const ORIGINAL_NODE_ENV = process.env.NODE_ENV;\n    const testValue = {}; // invalid value\n\n    process.env.NODE_ENV = 'development';\n    let [state, copyToClipboard] = hook.result.current;\n    act(() => copyToClipboard(testValue));\n    process.env.NODE_ENV = ORIGINAL_NODE_ENV;\n\n    [state, copyToClipboard] = hook.result.current;\n\n    expect(writeText).not.toBeCalled();\n    expect(consoleErrorSpy).toBeCalled();\n    expect(state.value).toBe(testValue);\n    expect(state.noUserInteraction).toBe(true);\n    expect(state.error).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "tests/useCounter.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useCounter from '../src/useCounter';\n\nconst setUp = (initialValue?: number, max: number | null = null, min: number | null = null) =>\n  renderHook(() => useCounter(initialValue, max, min));\n\nit('should init counter and utils', () => {\n  const { result } = setUp(5);\n\n  expect(result.current[0]).toBe(5);\n  expect(result.current[1]).toStrictEqual({\n    inc: expect.any(Function),\n    dec: expect.any(Function),\n    get: expect.any(Function),\n    set: expect.any(Function),\n    reset: expect.any(Function),\n  });\n});\n\nit('should init counter to 0 if not initial value received', () => {\n  const { result } = setUp();\n\n  expect(result.current[0]).toBe(0);\n});\n\nit('should init counter to negative number', () => {\n  const { result } = setUp(-2);\n\n  expect(result.current[0]).toBe(-2);\n});\n\nit('should get current counter', () => {\n  const { result } = setUp(5);\n  const { get } = result.current[1];\n\n  expect(get()).toBe(5);\n});\n\nit('should increment by 1 if not value received', () => {\n  const { result } = setUp(5);\n  const { get, inc } = result.current[1];\n\n  act(() => inc());\n\n  expect(result.current[0]).toBe(6);\n  expect(get()).toBe(6);\n});\n\nit('should increment by value received', () => {\n  const { result } = setUp(5);\n  const { get, inc } = result.current[1];\n\n  act(() => inc(9));\n\n  expect(result.current[0]).toBe(14);\n  expect(get()).toBe(14);\n});\n\nit('should decrement by 1 if not value received', () => {\n  const { result } = setUp(5);\n  const { get, dec } = result.current[1];\n\n  act(() => dec());\n\n  expect(result.current[0]).toBe(4);\n  expect(get()).toBe(4);\n});\n\nit('should decrement by value received', () => {\n  const { result } = setUp(5);\n  const { get, dec } = result.current[1];\n\n  act(() => dec(9));\n\n  expect(result.current[0]).toBe(-4);\n  expect(get()).toBe(-4);\n});\n\nit('should set to value received', () => {\n  const { result } = setUp(5);\n  const { get, set } = result.current[1];\n\n  act(() => set(17));\n\n  expect(result.current[0]).toBe(17);\n  expect(get()).toBe(17);\n});\n\nit('should reset to original value', () => {\n  const { result } = setUp(5);\n  const { get, set, reset } = result.current[1];\n\n  // set different value than initial one...\n  act(() => set(17));\n  expect(result.current[0]).toBe(17);\n\n  // ... and reset it to initial one\n  act(() => reset());\n  expect(result.current[0]).toBe(5);\n  expect(get()).toBe(5);\n});\n\nit('should reset and set new original value', () => {\n  const { result } = setUp(5);\n  const { get, set, reset } = result.current[1];\n\n  // set different value than initial one...\n  act(() => set(17));\n  expect(result.current[0]).toBe(17);\n\n  // ... now reset and set it to different than initial one...\n  act(() => reset(8));\n  expect(result.current[0]).toBe(8);\n\n  // ... and set different value than initial one again...\n  act(() => set(32));\n  expect(result.current[0]).toBe(32);\n\n  // ... and reset it to new initial value\n  act(() => reset());\n  expect(result.current[0]).toBe(8);\n  expect(get()).toBe(8);\n});\n\nit('should not exceed max value', () => {\n  const { result } = setUp(10, 5);\n  expect(result.current[0]).toBe(5);\n\n  const { get, inc, reset } = result.current[1];\n\n  act(() => reset(10));\n  expect(get()).toBe(5);\n\n  act(() => reset(4));\n  expect(get()).toBe(4);\n\n  act(() => inc());\n  expect(get()).toBe(5);\n\n  act(() => inc());\n  expect(get()).toBe(5);\n});\n\nit('should not exceed min value', () => {\n  const { result } = setUp(3, null, 5);\n  expect(result.current[0]).toBe(5);\n\n  const { get, dec, reset } = result.current[1];\n\n  act(() => reset(4));\n  expect(get()).toBe(5);\n\n  act(() => reset(6));\n  expect(get()).toBe(6);\n\n  act(() => dec());\n  expect(get()).toBe(5);\n\n  act(() => dec());\n  expect(get()).toBe(5);\n});\n\ndescribe('should `console.error` on unexpected inputs', () => {\n  it('on any of call parameters', () => {\n    const spy = jest.spyOn(console, 'error').mockImplementation(() => {});\n\n    // @ts-ignore\n    setUp(false);\n    expect(spy.mock.calls[0][0]).toBe('initialValue has to be a number, got boolean');\n\n    // @ts-ignore\n    setUp(10, false);\n    expect(spy.mock.calls[1][0]).toBe('max has to be a number, got boolean');\n\n    // @ts-ignore\n    setUp(10, 5, {});\n    expect(spy.mock.calls[2][0]).toBe('min has to be a number, got object');\n\n    spy.mockRestore();\n  });\n\n  it('on any of returned methods has unexpected input', () => {\n    const { result } = setUp(10);\n    const { inc, dec, reset } = result.current[1];\n\n    const spy = jest.spyOn(console, 'error').mockImplementation(() => {});\n\n    // @ts-ignore\n    act(() => inc(false));\n    expect(spy.mock.calls[0][0]).toBe(\n      'delta has to be a number or function returning a number, got boolean'\n    );\n\n    // @ts-ignore\n    act(() => dec(false));\n    expect(spy.mock.calls[1][0]).toBe(\n      'delta has to be a number or function returning a number, got boolean'\n    );\n\n    // @ts-ignore\n    act(() => reset({}));\n    expect(spy.mock.calls[2][0]).toBe(\n      'value has to be a number or function returning a number, got object'\n    );\n\n    spy.mockRestore();\n  });\n});\n"
  },
  {
    "path": "tests/useCustomCompareEffect.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useCustomCompareEffect } from '../src';\nimport { useEffect } from 'react';\nimport isDeepEqual from '../src/misc/isDeepEqual';\n\nlet options = { max: 10 };\nconst mockEffectNormal = jest.fn();\nconst mockEffectDeep = jest.fn();\nconst mockEffectCleanup = jest.fn();\nconst mockEffectCallback = jest.fn().mockReturnValue(mockEffectCleanup);\n\nit('should run provided object once', () => {\n  const { rerender: rerenderNormal } = renderHook(() => useEffect(mockEffectNormal, [options]));\n  const { rerender: rerenderDeep } = renderHook(() =>\n    useCustomCompareEffect(mockEffectDeep, [options], isDeepEqual)\n  );\n\n  expect(mockEffectNormal).toHaveBeenCalledTimes(1);\n  expect(mockEffectDeep).toHaveBeenCalledTimes(1);\n\n  options = { max: 10 };\n  rerenderDeep();\n  rerenderNormal();\n\n  expect(mockEffectNormal).toHaveBeenCalledTimes(2);\n  expect(mockEffectDeep).toHaveBeenCalledTimes(1);\n\n  options = { max: 10 };\n  rerenderNormal();\n  rerenderDeep();\n\n  expect(mockEffectNormal).toHaveBeenCalledTimes(3);\n  expect(mockEffectDeep).toHaveBeenCalledTimes(1);\n});\n\nit('should run clean-up provided on unmount', () => {\n  const { unmount } = renderHook(() =>\n    useCustomCompareEffect(mockEffectCallback, [options], isDeepEqual)\n  );\n  expect(mockEffectCleanup).not.toHaveBeenCalled();\n\n  unmount();\n  expect(mockEffectCleanup).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "tests/useDebounce.test.ts",
    "content": "import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks';\nimport { DependencyList } from 'react';\nimport { UseDebounceReturn } from '../src/useDebounce';\nimport { useDebounce } from '../src';\n\ndescribe('useDebounce', () => {\n  beforeAll(() => {\n    jest.useFakeTimers();\n  });\n\n  afterEach(() => {\n    jest.clearAllTimers();\n  });\n\n  afterAll(() => {\n    jest.useRealTimers();\n  });\n\n  it('should be defined', () => {\n    expect(useDebounce).toBeDefined();\n  });\n\n  it('should return two functions', () => {\n    const hook = renderHook(() => useDebounce(() => {}, 5));\n\n    expect(hook.result.current.length).toBe(2);\n    expect(typeof hook.result.current[0]).toBe('function');\n    expect(typeof hook.result.current[1]).toBe('function');\n  });\n\n  function getHook(\n    ms: number = 5,\n    dep: DependencyList = []\n  ): [jest.Mock, RenderHookResult<{ delay: number; deps: DependencyList }, UseDebounceReturn>] {\n    const spy = jest.fn();\n    return [\n      spy,\n      renderHook(({ delay = 5, deps = [] }) => useDebounce(spy, delay, deps), {\n        initialProps: {\n          delay: ms,\n          deps: dep,\n        },\n      }),\n    ];\n  }\n\n  it('should call passed function after given amount of time', () => {\n    const [spy] = getHook();\n\n    expect(spy).not.toHaveBeenCalled();\n    jest.advanceTimersByTime(5);\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n\n  it('should cancel function call on unmount', () => {\n    const [spy, hook] = getHook();\n\n    expect(spy).not.toHaveBeenCalled();\n    hook.unmount();\n    jest.advanceTimersByTime(5);\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('first function should return actual state of debounce', () => {\n    let [, hook] = getHook();\n    let [isReady] = hook.result.current;\n\n    expect(isReady()).toBe(false);\n    hook.unmount();\n    expect(isReady()).toBe(null);\n\n    [, hook] = getHook();\n    [isReady] = hook.result.current;\n    jest.advanceTimersByTime(5);\n    expect(isReady()).toBe(true);\n  });\n\n  it('second function should cancel debounce', () => {\n    const [spy, hook] = getHook();\n    const [isReady, cancel] = hook.result.current;\n\n    expect(spy).not.toHaveBeenCalled();\n    expect(isReady()).toBe(false);\n\n    act(() => {\n      cancel();\n    });\n    jest.advanceTimersByTime(5);\n\n    expect(spy).not.toHaveBeenCalled();\n    expect(isReady()).toBe(null);\n  });\n\n  it('should reset timeout on delay change', () => {\n    const [spy, hook] = getHook(50);\n\n    expect(spy).not.toHaveBeenCalled();\n    hook.rerender({ delay: 5, deps: [] });\n\n    jest.advanceTimersByTime(5);\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n\n  it('should reset timeout on deps change', () => {\n    const [spy, hook] = getHook(50, [5, 6]);\n\n    jest.advanceTimersByTime(45);\n    expect(spy).not.toHaveBeenCalled();\n    hook.rerender({ delay: 50, deps: [6, 6] });\n\n    jest.advanceTimersByTime(45);\n    expect(spy).not.toHaveBeenCalled();\n    jest.advanceTimersByTime(5);\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "tests/useDeepCompareEffect.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useDeepCompareEffect } from '../src';\nimport { useEffect } from 'react';\n\nlet options = { max: 10 };\nconst mockEffectNormal = jest.fn();\nconst mockEffectDeep = jest.fn();\nconst mockEffectCleanup = jest.fn();\nconst mockEffectCallback = jest.fn().mockReturnValue(mockEffectCleanup);\n\nit('should run provided object once', () => {\n  const { rerender: rerenderNormal } = renderHook(() => useEffect(mockEffectNormal, [options]));\n  const { rerender: rerenderDeep } = renderHook(() =>\n    useDeepCompareEffect(mockEffectDeep, [options])\n  );\n\n  expect(mockEffectNormal).toHaveBeenCalledTimes(1);\n  expect(mockEffectDeep).toHaveBeenCalledTimes(1);\n\n  options = { max: 10 };\n  rerenderDeep();\n  rerenderNormal();\n\n  expect(mockEffectNormal).toHaveBeenCalledTimes(2);\n  expect(mockEffectDeep).toHaveBeenCalledTimes(1);\n\n  options = { max: 10 };\n  rerenderNormal();\n  rerenderDeep();\n\n  expect(mockEffectNormal).toHaveBeenCalledTimes(3);\n  expect(mockEffectDeep).toHaveBeenCalledTimes(1);\n});\n\nit('should run clean-up provided on unmount', () => {\n  const { unmount } = renderHook(() => useDeepCompareEffect(mockEffectCallback, [options]));\n  expect(mockEffectCleanup).not.toHaveBeenCalled();\n\n  unmount();\n  expect(mockEffectCleanup).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "tests/useDefault.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useDefault from '../src/useDefault';\n\nconst setUp = (defaultValue: any, initialValue: any) =>\n  renderHook(() => useDefault(defaultValue, initialValue));\n\ndescribe.each`\n  valueType    | defaultValue | initialValue            | anotherValue\n  ${'number'}  | ${0}         | ${5}                    | ${77}\n  ${'object'}  | ${{}}        | ${{ name: 'John Doe' }} | ${{ name: 'Solid Snake' }}\n  ${'boolean'} | ${false}     | ${false}                | ${true}\n  ${'string'}  | ${''}        | ${'foo'}                | ${'bar'}\n`('when value type is $valueType', ({ defaultValue, initialValue, anotherValue }) => {\n  it('should init state with initial value', () => {\n    const { result } = setUp(defaultValue, initialValue);\n    const [value, setValue] = result.current;\n\n    expect(value).toBe(initialValue);\n    expect(setValue).toBeInstanceOf(Function);\n  });\n\n  it('should set state to another value', () => {\n    const { result } = setUp(defaultValue, initialValue);\n    const [, setValue] = result.current;\n\n    act(() => setValue(anotherValue));\n\n    expect(result.current[0]).toBe(anotherValue);\n  });\n\n  it('should return default value if state set to null', () => {\n    const { result } = setUp(defaultValue, initialValue);\n    const [, setValue] = result.current;\n\n    act(() => setValue(null));\n\n    expect(result.current[0]).toBe(defaultValue);\n  });\n\n  it('should return default value if state set to undefined', () => {\n    const { result } = setUp(defaultValue, initialValue);\n    const [, setValue] = result.current;\n\n    act(() => setValue(undefined));\n\n    expect(result.current[0]).toBe(defaultValue);\n  });\n\n  it('should handle state properly after being set to nil and then to another value', () => {\n    const { result } = setUp(defaultValue, initialValue);\n    const [, setValue] = result.current;\n\n    act(() => setValue(undefined));\n    expect(result.current[0]).toBe(defaultValue);\n\n    act(() => setValue(null));\n    expect(result.current[0]).toBe(defaultValue);\n\n    act(() => setValue(anotherValue));\n    expect(result.current[0]).toBe(anotherValue);\n  });\n});\n"
  },
  {
    "path": "tests/useEffectOnce.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useEffectOnce } from '../src';\n\nconst mockEffectCleanup = jest.fn();\nconst mockEffectCallback = jest.fn().mockReturnValue(mockEffectCleanup);\n\nit('should run provided effect only once', () => {\n  const { rerender } = renderHook(() => useEffectOnce(mockEffectCallback));\n  expect(mockEffectCallback).toHaveBeenCalledTimes(1);\n\n  rerender();\n  expect(mockEffectCallback).toHaveBeenCalledTimes(1);\n});\n\nit('should run clean-up provided on unmount', () => {\n  const { unmount } = renderHook(() => useEffectOnce(mockEffectCallback));\n  expect(mockEffectCleanup).not.toHaveBeenCalled();\n\n  unmount();\n  expect(mockEffectCleanup).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "tests/useEnsuredForwardedRef.test.tsx",
    "content": "import React, { useRef } from 'react';\nimport ReactDOM from 'react-dom';\nimport { renderHook } from '@testing-library/react-hooks';\nimport TestUtils from 'react-dom/test-utils';\nimport { ensuredForwardRef, useEnsuredForwardedRef } from '../src';\n\nlet container: HTMLDivElement;\n\nbeforeEach(() => {\n  container = document.createElement('div');\n  document.body.appendChild(container);\n});\n\nafterEach(() => {\n  document.body.removeChild(container);\n  container = null!;\n});\n\ntest('should return a valid ref with existing forwardedRef', () => {\n  const { result } = renderHook(() => {\n    const ref = useRef(null);\n    const ensuredRef = useEnsuredForwardedRef(ref);\n\n    TestUtils.act(() => {\n      ReactDOM.render(<div ref={ensuredRef} />, container);\n    });\n\n    return {\n      initialRef: ref,\n      ensuredForwardedRef: ensuredRef,\n    };\n  });\n\n  const { initialRef, ensuredForwardedRef } = result.current;\n\n  expect(ensuredForwardedRef).toStrictEqual(initialRef);\n});\n\ntest('should return a valid ref when the forwarded ref is undefined', () => {\n  const { result } = renderHook(() => {\n    const ref = useEnsuredForwardedRef<HTMLDivElement>(undefined!);\n\n    TestUtils.act(() => {\n      ReactDOM.render(<div id=\"test_id\" ref={ref} />, container);\n    });\n\n    return { ensuredRef: ref };\n  });\n\n  const { ensuredRef } = result.current;\n\n  expect(ensuredRef.current.id).toBe('test_id');\n});\n\ntest('should return a valid ref when using the wrapper function style', () => {\n  const { result } = renderHook(() => {\n    const initialRef = useRef<HTMLDivElement | null>(null);\n\n    const WrappedComponent = ensuredForwardRef<HTMLDivElement>((_props, ref) => {\n      return <div id=\"test_id\" ref={ref} />;\n    });\n\n    TestUtils.act(() => {\n      ReactDOM.render(<WrappedComponent ref={initialRef} />, container);\n    });\n\n    return { initialRef };\n  });\n\n  const { initialRef } = result.current;\n\n  expect(initialRef.current).toBeTruthy();\n  expect(initialRef.current?.id).toBe('test_id');\n});\n"
  },
  {
    "path": "tests/useError.test.ts",
    "content": "import { renderHook, act } from '@testing-library/react-hooks';\nimport { useError } from '../src';\n\nconst setup = () => renderHook(() => useError());\n\nbeforeEach(() => {\n  jest.spyOn(console, 'error').mockImplementation(() => {});\n});\n\nafterEach(() => {\n  jest.clearAllMocks();\n});\n\nit('should throw an error on error dispatch', () => {\n  const errorStr = 'some_error';\n\n  try {\n    const { result } = setup();\n\n    act(() => {\n      result.current(new Error(errorStr));\n    });\n  } catch (err) {\n    expect(err.message).toEqual(errorStr);\n  }\n});\n"
  },
  {
    "path": "tests/useEvent.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport useEvent, { ListenerType1, ListenerType2 } from '../src/useEvent';\n\ninterface Props {\n  name: string;\n  handler: (...args: any[]) => void;\n  target: ListenerType1 | ListenerType2;\n  options: any;\n}\n\nconst propsList1 = [\n  {\n    name: 'name1',\n    handler: () => {},\n    target: {\n      addEventListener: jest.fn(),\n      removeEventListener: jest.fn(),\n    },\n    options: { a: 'opt1' },\n  },\n  {\n    name: 'name2',\n    handler: () => {},\n    target: {\n      addEventListener: jest.fn(),\n      removeEventListener: jest.fn(),\n    },\n    options: { a: 'opt2' },\n  },\n];\n\nconst propsList2 = [\n  {\n    ...propsList1[0],\n    target: {\n      on: jest.fn(),\n      off: jest.fn(),\n    },\n  },\n  {\n    ...propsList1[1],\n    target: {\n      on: jest.fn(),\n      off: jest.fn(),\n    },\n  },\n];\n\nit('should call addEventListener/removeEventListener on mount/unmount', () => {\n  checkOnMountAndUnmount(propsList1[0], 'addEventListener', 'removeEventListener');\n});\n\nit('should call on/off on mount/unmount', () => {\n  checkOnMountAndUnmount(propsList2[0], 'on', 'off');\n});\n\nit('should call addEventListener/removeEventListener on deps changes', () => {\n  checkOnDepsChanges(propsList1[0], propsList1[1], 'addEventListener', 'removeEventListener');\n});\n\nit('should call on/off on deps changes', () => {\n  checkOnDepsChanges(propsList2[0], propsList2[1], 'on', 'off');\n});\n\nconst checkOnMountAndUnmount = (\n  props: Props,\n  addEventListenerName: string,\n  removeEventListenerName: string\n) => {\n  const { unmount } = renderHook((p: Props) => useEvent(p.name, p.handler, p.target, p.options), {\n    initialProps: props,\n  });\n  expect(props.target[addEventListenerName]).toHaveBeenCalledTimes(1);\n  expect(props.target[addEventListenerName]).toHaveBeenLastCalledWith(\n    props.name,\n    props.handler,\n    props.options\n  );\n  unmount();\n  expect(props.target[removeEventListenerName]).toHaveBeenCalledTimes(1);\n  expect(props.target[removeEventListenerName]).toHaveBeenLastCalledWith(\n    props.name,\n    props.handler,\n    props.options\n  );\n};\n\nconst checkOnDepsChanges = (\n  props1: Props,\n  props2: Props,\n  addEventListenerName: string,\n  removeEventListenerName: string\n) => {\n  const { rerender } = renderHook((p: Props) => useEvent(p.name, p.handler, p.target, p.options), {\n    initialProps: props1,\n  });\n  expect(props1.target[addEventListenerName]).toHaveBeenCalledTimes(1);\n  expect(props1.target[addEventListenerName]).toHaveBeenLastCalledWith(\n    props1.name,\n    props1.handler,\n    props1.options\n  );\n\n  // deps are same as previous\n  rerender({\n    name: props1.name,\n    handler: props1.handler,\n    target: props1.target,\n    options: props1.options,\n  });\n  expect(props1.target[removeEventListenerName]).not.toHaveBeenCalled();\n\n  // name is different from previous\n  rerender({\n    name: props2.name,\n    handler: props1.handler,\n    target: props1.target,\n    options: props1.options,\n  });\n  expect(props1.target[removeEventListenerName]).toHaveBeenCalledTimes(1);\n  expect(props1.target[removeEventListenerName]).toHaveBeenLastCalledWith(\n    props1.name,\n    props1.handler,\n    props1.options\n  );\n\n  // handler is different from previous\n  rerender({\n    name: props2.name,\n    handler: props2.handler,\n    target: props1.target,\n    options: props1.options,\n  });\n  expect(props1.target[removeEventListenerName]).toHaveBeenCalledTimes(2);\n  expect(props1.target[removeEventListenerName]).toHaveBeenLastCalledWith(\n    props2.name,\n    props1.handler,\n    props1.options\n  );\n\n  // options contents is same as previous\n  rerender({\n    name: props2.name,\n    handler: props2.handler,\n    target: props1.target,\n    options: { a: 'opt1' },\n  });\n  expect(props1.target[removeEventListenerName]).toHaveBeenCalledTimes(2);\n\n  // options is different from previous\n  rerender({\n    name: props2.name,\n    handler: props2.handler,\n    target: props1.target,\n    options: props2.options,\n  });\n  expect(props1.target[removeEventListenerName]).toHaveBeenCalledTimes(3);\n  expect(props1.target[removeEventListenerName]).toHaveBeenLastCalledWith(\n    props2.name,\n    props2.handler,\n    props1.options\n  );\n\n  // target is different from previous\n  rerender({\n    name: props2.name,\n    handler: props2.handler,\n    target: props2.target,\n    options: props2.options,\n  });\n  expect(props1.target[removeEventListenerName]).toHaveBeenCalledTimes(4);\n  expect(props1.target[removeEventListenerName]).toHaveBeenLastCalledWith(\n    props2.name,\n    props2.handler,\n    props2.options\n  );\n\n  expect(props2.target[addEventListenerName]).toHaveBeenCalledTimes(1);\n  expect(props2.target[addEventListenerName]).toHaveBeenLastCalledWith(\n    props2.name,\n    props2.handler,\n    props2.options\n  );\n};\n"
  },
  {
    "path": "tests/useFavicon.test.tsx",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport useFavicon from '../src/useFavicon';\n\nafterEach(() => {\n  const favicon = document.querySelector(\"link[rel*='icon']\");\n  if (favicon) {\n    favicon.remove();\n  }\n});\n\ndescribe('useFavicon', () => {\n  it('should be defined', () => {\n    expect(useFavicon).toBeDefined();\n  });\n\n  it('should create a HTMLLinkElement', () => {\n    const faviconBeforeHook = document.querySelector(\"link[rel*='icon']\");\n\n    expect(faviconBeforeHook).toBe(null);\n    renderHook(() => useFavicon('My-favicon'));\n\n    const faviconAfterHook = document.querySelector(\"link[rel*='icon']\");\n    expect(faviconAfterHook).toBeInstanceOf(HTMLLinkElement);\n  });\n\n  it('should set the elements type to \"image/x-icon\"', () => {\n    renderHook(() => useFavicon('My-favicon'));\n    const favicon = document.querySelector(\"link[rel*='icon']\") as HTMLLinkElement;\n\n    expect(favicon.type).toBe('image/x-icon');\n  });\n\n  it('should set the elements rel to \"shortcut icon\"', () => {\n    renderHook(() => useFavicon('My-favicon'));\n    const favicon = document.querySelector(\"link[rel*='icon']\") as HTMLLinkElement;\n\n    expect(favicon.rel).toBe('shortcut icon');\n  });\n\n  it('should set the elements href to the provided string', () => {\n    renderHook(() => useFavicon('https://github.com/streamich/react-use'));\n    const favicon = document.querySelector(\"link[rel*='icon']\") as HTMLLinkElement;\n\n    expect(favicon.href).toBe('https://github.com/streamich/react-use');\n  });\n\n  it('should update an existing favicon', () => {\n    const hook = renderHook((props) => useFavicon(props), {\n      initialProps: 'https://github.com/streamich/react-use',\n    });\n    const favicon = document.querySelector(\"link[rel*='icon']\") as HTMLLinkElement;\n\n    expect(favicon.href).toBe('https://github.com/streamich/react-use');\n    hook.rerender('https://en.wikipedia.org/wiki/Favicon');\n    expect(favicon.href).toBe('https://en.wikipedia.org/wiki/Favicon');\n  });\n});\n"
  },
  {
    "path": "tests/useFirstMountState.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useFirstMountState } from '../src';\n\ndescribe('useFirstMountState', () => {\n  it('should be defined', () => {\n    expect(useFirstMountState).toBeDefined();\n  });\n\n  it('should return boolean', () => {\n    expect(renderHook(() => useFirstMountState()).result.current).toEqual(expect.any(Boolean));\n  });\n\n  it('should return true on first render and false on all others', () => {\n    const hook = renderHook(() => useFirstMountState());\n\n    expect(hook.result.current).toBe(true);\n    hook.rerender();\n    expect(hook.result.current).toBe(false);\n    hook.rerender();\n    expect(hook.result.current).toBe(false);\n  });\n});\n"
  },
  {
    "path": "tests/useGetSet.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useGetSet from '../src/useGetSet';\n\nconst setUp = (initialValue: any) => renderHook(() => useGetSet(initialValue));\n\nbeforeEach(() => {\n  jest.useFakeTimers();\n});\n\nit('should init getter and setter', () => {\n  const { result } = setUp('foo');\n  const [get, set] = result.current;\n\n  expect(get).toBeInstanceOf(Function);\n  expect(set).toBeInstanceOf(Function);\n});\n\nit('should get current value', () => {\n  const { result } = setUp('foo');\n  const [get] = result.current;\n\n  const currentValue = get();\n\n  expect(currentValue).toBe('foo');\n});\n\nit('should set new value', () => {\n  const { result } = setUp('foo');\n  const [get, set] = result.current;\n\n  act(() => set('bar'));\n\n  const currentValue = get();\n  expect(currentValue).toBe('bar');\n});\n\n/**\n * This test implements the special demo in storybook that increments a number\n * after 1 second on each click.\n */\nit('should get and set expected values when used in nested functions', () => {\n  const onClick = jest.fn(() => {\n    setTimeout(() => {\n      set(get() + 1);\n    }, 1000);\n  });\n\n  const { result } = setUp(0);\n  const [get, set] = result.current;\n\n  // simulate 3 clicks\n  onClick();\n  onClick();\n  onClick();\n\n  // fast-forward until all timers have been executed\n  act(() => {\n    jest.runAllTimers();\n  });\n\n  const currentValue = get();\n  expect(currentValue).toBe(3);\n  expect(onClick).toHaveBeenCalledTimes(3);\n});\n"
  },
  {
    "path": "tests/useGetSetState.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useGetSetState from '../src/useGetSetState';\n\nconst originalConsoleError = console.error;\nconst mockConsoleError = jest.fn();\n\nconst setUp = (initialState: any) => renderHook(() => useGetSetState(initialState));\n\nbeforeAll(() => {\n  console.error = mockConsoleError;\n});\n\nafterAll(() => {\n  console.error = originalConsoleError;\n});\n\nbeforeEach(() => {\n  jest.useFakeTimers();\n});\n\nit('should init getter and setter', () => {\n  const { result } = setUp({ foo: 'initialValue' });\n  const [get, set] = result.current;\n\n  expect(get).toBeInstanceOf(Function);\n  expect(set).toBeInstanceOf(Function);\n});\n\nit('should log an error if init with something different than an object', () => {\n  expect(mockConsoleError).not.toHaveBeenCalled();\n\n  setUp('not an object');\n\n  expect(mockConsoleError).toHaveBeenCalledTimes(1);\n  expect(mockConsoleError).toHaveBeenCalledWith('useGetSetState initial state must be an object.');\n});\n\nit('should get current state', () => {\n  const { result } = setUp({ foo: 'a', bar: 'z' });\n  const [get] = result.current;\n\n  const currentState = get();\n\n  expect(currentState).toEqual({ foo: 'a', bar: 'z' });\n});\n\nit('should set new state by applying patch with existing keys', () => {\n  const { result } = setUp({ foo: 'a', bar: 'z' });\n  const [get, set] = result.current;\n\n  act(() => set({ bar: 'y' }));\n\n  const currentState = get();\n  expect(currentState).toEqual({ foo: 'a', bar: 'y' });\n});\n\nit('should set new state by applying patch with new keys', () => {\n  const { result } = setUp({ foo: 'a', bar: 'z' });\n  const [get, set] = result.current;\n\n  act(() => set({ qux: 'f' }));\n\n  const currentState = get();\n  expect(currentState).toEqual({ foo: 'a', bar: 'z', qux: 'f' });\n});\n\nit('should set new state by applying patch with both new and old keys', () => {\n  const { result } = setUp({ foo: 'a', bar: 'z' });\n  const [get, set] = result.current;\n\n  act(() => set({ bar: 'y', qux: 'f' }));\n\n  const currentState = get();\n  expect(currentState).toEqual({ foo: 'a', bar: 'y', qux: 'f' });\n});\n\nit('should NOT set new state if empty patch received', () => {\n  const { result } = setUp({ foo: 'a', bar: 'z' });\n  const [get, set] = result.current;\n\n  act(() => set({}));\n\n  const currentState = get();\n  expect(currentState).toEqual({ foo: 'a', bar: 'z' });\n});\n\nit('should NOT set new state if no patch received', () => {\n  const { result } = setUp({ foo: 'a', bar: 'z' });\n  const [get, set] = result.current;\n\n  // @ts-ignore\n  act(() => set());\n\n  const currentState = get();\n  expect(currentState).toEqual({ foo: 'a', bar: 'z' });\n});\n\nit('should log an error if set with a patch different than an object', () => {\n  const { result } = setUp({ foo: 'a', bar: 'z' });\n  const [, set] = result.current;\n  expect(mockConsoleError).not.toHaveBeenCalled();\n\n  act(() => set('not an object' as any));\n\n  expect(mockConsoleError).toHaveBeenCalledTimes(1);\n  expect(mockConsoleError).toHaveBeenCalledWith('useGetSetState setter patch must be an object.');\n});\n\n/**\n * This test is equivalent to demo one for `useGetSet` hook.\n */\nit('should get and set expected state when used in nested functions', () => {\n  const onClick = jest.fn(() => {\n    setTimeout(() => {\n      set({ counter: get().counter + 1 });\n    }, 1000);\n  });\n\n  const { result } = setUp({ counter: 0 });\n  const [get, set] = result.current;\n\n  // simulate 3 clicks\n  onClick();\n  onClick();\n  onClick();\n\n  // fast-forward until all timers have been executed\n  act(() => {\n    jest.runAllTimers();\n  });\n\n  const currentState = get();\n  expect(currentState).toEqual({ counter: 3 });\n  expect(onClick).toHaveBeenCalledTimes(3);\n});\n"
  },
  {
    "path": "tests/useHash.test.ts",
    "content": "import { renderHook, act } from '@testing-library/react-hooks';\nimport { useHash } from '../src/useHash';\n\n(global as any).window = Object.create(window);\nlet mockHash = '#';\nconst mockLocation = {};\nObject.defineProperty(mockLocation, 'hash', {\n  get() {\n    return mockHash;\n  },\n  set(newHash) {\n    mockHash = newHash;\n    window.dispatchEvent(new HashChangeEvent('hashchange'));\n  },\n});\nObject.defineProperty(window, 'location', {\n  value: mockLocation,\n});\n\nbeforeEach(() => {\n  window.location.hash = '#';\n});\n\ntest('returns current url hash', () => {\n  window.location.hash = '#abc';\n\n  const { result } = renderHook(() => useHash());\n\n  const hash = result.current[0];\n  expect(hash).toBe('#abc');\n});\n\ntest('returns latest url hash when change the hash with setHash', () => {\n  const { result } = renderHook(() => useHash());\n  const hash = result.current[0];\n  const setHash = result.current[1];\n  expect(hash).toBe('#');\n  act(() => {\n    setHash('#abc');\n  });\n  const hash2 = result.current[0];\n  expect(hash2).toBe('#abc');\n});\n\nit('returns latest url hash when change the hash with \"hashchange\" event', () => {\n  const { result } = renderHook(() => useHash());\n  const hash = result.current[0];\n  expect(hash).toBe('#');\n  act(() => {\n    window.location.hash = '#abc';\n  });\n  const hash2 = result.current[0];\n  expect(hash2).toBe('#abc');\n});\n"
  },
  {
    "path": "tests/useIntersection.test.tsx",
    "content": "import React, { createRef } from 'react';\nimport ReactDOM from 'react-dom';\nimport TestUtils from 'react-dom/test-utils';\nimport TestRenderer from 'react-test-renderer';\nimport { intersectionObserver } from '@shopify/jest-dom-mocks';\nimport { renderHook } from '@testing-library/react-hooks';\nimport { useIntersection } from '../src';\n\nbeforeEach(() => {\n  intersectionObserver.mock();\n  const IO = IntersectionObserver;\n  jest.spyOn(IO.prototype, 'disconnect');\n  jest.spyOn(global as any, 'IntersectionObserver');\n  IntersectionObserver.prototype = IO.prototype;\n});\n\nafterEach(() => {\n  intersectionObserver.restore();\n});\n\ndescribe('useIntersection', () => {\n  const container = document.createElement('div');\n  let targetRef;\n\n  it('should be defined', () => {\n    expect(useIntersection).toBeDefined();\n  });\n\n  it('should setup an IntersectionObserver targeting the ref element and using the options provided', () => {\n    TestUtils.act(() => {\n      targetRef = createRef();\n      ReactDOM.render(<div ref={targetRef} />, container);\n    });\n\n    expect(intersectionObserver.observers).toHaveLength(0);\n    const observerOptions = { root: null, threshold: 0.8 };\n\n    renderHook(() => useIntersection(targetRef, observerOptions));\n\n    expect(intersectionObserver.observers).toHaveLength(1);\n    expect(intersectionObserver.observers[0].target).toEqual(targetRef.current);\n    expect(intersectionObserver.observers[0].options).toEqual(observerOptions);\n  });\n\n  it('should return null if a ref without a current value is provided', () => {\n    targetRef = createRef();\n\n    const { result } = renderHook(() => useIntersection(targetRef, { root: null, threshold: 1 }));\n    expect(result.current).toBe(null);\n  });\n\n  it('should reset an intersectionObserverEntry when the ref changes', () => {\n    TestUtils.act(() => {\n      targetRef = createRef();\n      ReactDOM.render(<div ref={targetRef} />, container);\n    });\n\n    const { result, rerender } = renderHook(() =>\n      useIntersection(targetRef, { root: container, threshold: 0.8 })\n    );\n\n    const mockIntersectionObserverEntry = {\n      boundingClientRect: targetRef.current.getBoundingClientRect(),\n      intersectionRatio: 0.81,\n      intersectionRect: container.getBoundingClientRect(),\n      isIntersecting: true,\n      rootBounds: container.getBoundingClientRect(),\n      target: targetRef.current,\n      time: 300,\n    };\n    TestRenderer.act(() => {\n      intersectionObserver.simulate(mockIntersectionObserverEntry);\n    });\n\n    expect(result.current).toEqual(mockIntersectionObserverEntry);\n\n    targetRef.current = document.createElement('div');\n    rerender();\n\n    expect(result.current).toEqual(null);\n  });\n\n  it('should return null if IntersectionObserver is not supported', () => {\n    targetRef = createRef();\n    targetRef.current = document.createElement('div');\n    delete (window as any).IntersectionObserver;\n\n    expect(() => renderHook(() => useIntersection(targetRef, {}))).not.toThrow();\n  });\n\n  it('should disconnect an old IntersectionObserver instance when the ref changes', () => {\n    targetRef = createRef();\n    targetRef.current = document.createElement('div');\n\n    const { rerender } = renderHook(() => useIntersection(targetRef, {}));\n\n    targetRef.current = document.createElement('div');\n    rerender();\n\n    targetRef.current = null;\n    rerender();\n\n    expect(IntersectionObserver).toHaveBeenCalledTimes(2);\n    expect(IntersectionObserver.prototype.disconnect).toHaveBeenCalledTimes(2);\n  });\n\n  it('should return the first IntersectionObserverEntry when the IntersectionObserver registers an intersection', () => {\n    TestUtils.act(() => {\n      targetRef = createRef();\n      ReactDOM.render(<div ref={targetRef} />, container);\n    });\n\n    const { result } = renderHook(() =>\n      useIntersection(targetRef, { root: container, threshold: 0.8 })\n    );\n\n    const mockIntersectionObserverEntry = {\n      boundingClientRect: targetRef.current.getBoundingClientRect(),\n      intersectionRatio: 0.81,\n      intersectionRect: container.getBoundingClientRect(),\n      isIntersecting: true,\n      rootBounds: container.getBoundingClientRect(),\n      target: targetRef.current,\n      time: 300,\n    };\n    TestRenderer.act(() => {\n      intersectionObserver.simulate(mockIntersectionObserverEntry);\n    });\n\n    expect(result.current).toEqual(mockIntersectionObserverEntry);\n  });\n\n  it('should setup a new IntersectionObserver when the ref changes', () => {\n    let newRef;\n    TestUtils.act(() => {\n      targetRef = createRef();\n      newRef = createRef();\n      ReactDOM.render(\n        <div ref={targetRef}>\n          <span ref={newRef} />\n        </div>,\n        container\n      );\n    });\n\n    const observerOptions = { root: null, threshold: 0.8 };\n    const { rerender } = renderHook(({ ref, options }) => useIntersection(ref, options), {\n      initialProps: { ref: targetRef, options: observerOptions },\n    });\n\n    expect(intersectionObserver.observers[0].target).toEqual(targetRef.current);\n\n    TestRenderer.act(() => {\n      rerender({ ref: newRef, options: observerOptions });\n    });\n\n    expect(intersectionObserver.observers[0].target).toEqual(newRef.current);\n  });\n\n  it('should setup a new IntersectionObserver when the options change', () => {\n    TestUtils.act(() => {\n      targetRef = createRef();\n      ReactDOM.render(<div ref={targetRef} />, container);\n    });\n\n    const initialObserverOptions = { root: null as HTMLElement | null, threshold: 0.8 };\n    const { rerender } = renderHook(({ ref, options }) => useIntersection(ref, options), {\n      initialProps: { ref: targetRef, options: initialObserverOptions },\n    });\n\n    expect(intersectionObserver.observers[0].options).toEqual(initialObserverOptions);\n\n    const newObserverOptions = { root: container, threshold: 1 };\n    TestRenderer.act(() => {\n      rerender({ ref: targetRef, options: newObserverOptions });\n    });\n\n    expect(intersectionObserver.observers[0].options).toEqual(newObserverOptions);\n  });\n});\n"
  },
  {
    "path": "tests/useInterval.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useInterval } from '../src';\n\nlet callback;\n\nbeforeEach(() => {\n  callback = jest.fn();\n});\n\nbeforeAll(() => {\n  jest.useFakeTimers();\n});\n\nafterEach(() => {\n  callback.mockRestore();\n  jest.clearAllTimers();\n});\n\nafterAll(() => {\n  jest.useRealTimers();\n});\n\nit('should init hook with default delay', () => {\n  const { result } = renderHook(() => useInterval(callback));\n\n  expect(result.current).toBeUndefined();\n  expect(setInterval).toHaveBeenCalledTimes(1);\n  // if not delay provided, it's assumed as 0\n  expect(setInterval).toHaveBeenCalledWith(expect.any(Function), 0);\n});\n\nit('should init hook with custom delay', () => {\n  const { result } = renderHook(() => useInterval(callback, 5000));\n\n  expect(result.current).toBeUndefined();\n  expect(setInterval).toHaveBeenCalledTimes(1);\n  expect(setInterval).toHaveBeenCalledWith(expect.any(Function), 5000);\n});\n\nit('should init hook without delay', () => {\n  const { result } = renderHook(() => useInterval(callback, null));\n\n  expect(result.current).toBeUndefined();\n  // if null delay provided, it's assumed as no delay\n  expect(setInterval).not.toHaveBeenCalled();\n});\n\nit('should repeatedly calls provided callback with a fixed time delay between each call', () => {\n  renderHook(() => useInterval(callback, 200));\n  expect(callback).not.toHaveBeenCalled();\n\n  // fast-forward time until 1s before it should be executed\n  jest.advanceTimersByTime(199);\n  expect(callback).not.toHaveBeenCalled();\n\n  // fast-forward until 1st call should be executed\n  jest.advanceTimersByTime(1);\n  expect(callback).toHaveBeenCalledTimes(1);\n\n  // fast-forward until next timer should be executed\n  jest.advanceTimersToNextTimer();\n  expect(callback).toHaveBeenCalledTimes(2);\n\n  // fast-forward until 3 more timers should be executed\n  jest.advanceTimersToNextTimer(3);\n  expect(callback).toHaveBeenCalledTimes(5);\n});\n\nit('should clear interval on unmount', () => {\n  const { unmount } = renderHook(() => useInterval(callback, 200));\n  const initialTimerCount = jest.getTimerCount();\n  expect(clearInterval).not.toHaveBeenCalled();\n\n  unmount();\n\n  expect(clearInterval).toHaveBeenCalledTimes(1);\n  expect(jest.getTimerCount()).toBe(initialTimerCount - 1);\n});\n\nit('should handle new interval when delay is updated', () => {\n  let delay = 200;\n  const { rerender } = renderHook(() => useInterval(callback, delay));\n  expect(callback).not.toHaveBeenCalled();\n\n  // fast-forward initial delay\n  jest.advanceTimersByTime(200);\n  expect(callback).toHaveBeenCalledTimes(1);\n\n  // update delay by increasing previous one\n  delay = 500;\n  rerender();\n\n  // fast-forward initial delay again but this time it should not execute the cb\n  jest.advanceTimersByTime(200);\n  expect(callback).toHaveBeenCalledTimes(1);\n\n  // fast-forward remaining time for new delay\n  jest.advanceTimersByTime(300);\n  expect(callback).toHaveBeenCalledTimes(2);\n});\n\nit('should clear pending interval when delay is updated', () => {\n  let delay = 200;\n  const { rerender } = renderHook(() => useInterval(callback, delay));\n  expect(clearInterval).not.toHaveBeenCalled();\n  const initialTimerCount = jest.getTimerCount();\n\n  // update delay while there is a pending interval\n  delay = 500;\n  rerender();\n\n  expect(clearInterval).toHaveBeenCalledTimes(1);\n  expect(jest.getTimerCount()).toBe(initialTimerCount);\n});\n"
  },
  {
    "path": "tests/useLatest.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport useLatest from '../src/useLatest';\n\nconst setUp = () => renderHook(({ state }) => useLatest(state), { initialProps: { state: 0 } });\n\nit('should return a ref with the latest value on initial render', () => {\n  const { result } = setUp();\n\n  expect(result.current).toEqual({ current: 0 });\n});\n\nit('should always return a ref with the latest value after each update', () => {\n  const { result, rerender } = setUp();\n\n  rerender({ state: 2 });\n  expect(result.current).toEqual({ current: 2 });\n\n  rerender({ state: 4 });\n  expect(result.current).toEqual({ current: 4 });\n\n  rerender({ state: 6 });\n  expect(result.current).toEqual({ current: 6 });\n});\n"
  },
  {
    "path": "tests/useList.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport { useRef } from 'react';\nimport useList, { ListActions } from '../src/useList';\n\ndescribe('useList', () => {\n  it('should be defined', () => {\n    expect(useList).toBeDefined();\n  });\n\n  function getHook<T>(initialArray?: T[]) {\n    return renderHook(\n      (props): [number, [T[], ListActions<T>]] => {\n        const counter = useRef(0);\n\n        return [++counter.current, useList(props)];\n      },\n      { initialProps: initialArray }\n    );\n  }\n\n  it('should init with 1st parameter and actions', () => {\n    const hook = getHook([1, 2, 3]);\n    const [, [list, actions]] = hook.result.current;\n\n    expect(list).toEqual([1, 2, 3]);\n    expect(actions).toStrictEqual({\n      set: expect.any(Function),\n      push: expect.any(Function),\n      updateAt: expect.any(Function),\n      insertAt: expect.any(Function),\n      update: expect.any(Function),\n      updateFirst: expect.any(Function),\n      upsert: expect.any(Function),\n      sort: expect.any(Function),\n      filter: expect.any(Function),\n      removeAt: expect.any(Function),\n      remove: expect.any(Function),\n      clear: expect.any(Function),\n      reset: expect.any(Function),\n    });\n  });\n\n  it('should return the same actions object each render', () => {\n    const hook = getHook([1, 2, 3]);\n    const [, [, actions]] = hook.result.current;\n\n    act(() => {\n      actions.set([1, 2, 3, 4]);\n    });\n\n    expect(actions).toBe(hook.result.current[1][1]);\n  });\n\n  it('should default with empty array', () => {\n    expect(getHook().result.current[1][0]).toEqual([]);\n  });\n\n  describe('set()', () => {\n    it('should reset list with given array and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { set }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        set([1, 2, 3, 4]);\n      });\n      expect(hook.result.current[1][0]).toEqual([1, 2, 3, 4]);\n      expect(hook.result.current[0]).toBe(2);\n\n      act(() => {\n        set([1, 2, 3, 4, 5]);\n      });\n      expect(hook.result.current[1][0]).toEqual([1, 2, 3, 4, 5]);\n      expect(hook.result.current[0]).toBe(3);\n    });\n  });\n\n  describe('push()', () => {\n    it('should add arbitrary amount of items to the end and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { push }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        push(1, 2, 3, 4);\n      });\n      expect(hook.result.current[1][0]).toEqual([1, 2, 3, 1, 2, 3, 4]);\n      expect(hook.result.current[0]).toBe(2);\n    });\n\n    it('should not do anything if called with no parameters', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [list, { push }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        push();\n      });\n      expect(hook.result.current[0]).toBe(1);\n      expect(list).toBe(hook.result.current[1][0]);\n    });\n  });\n\n  describe('updateAt()', () => {\n    it('should replace item at given index with given value and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { updateAt }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        updateAt(1, 5);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([1, 5, 3]);\n    });\n\n    it('should work fine if target index is out of array length', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { updateAt }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        updateAt(5, 6);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([1, 2, 3, undefined, undefined, 6]);\n    });\n  });\n\n  describe('insertAt()', () => {\n    it('should insert item at given index shifting all the right elements and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { insertAt }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        insertAt(1, 5);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([1, 5, 2, 3]);\n    });\n\n    it('should work if index is out of array length', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { insertAt }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        insertAt(5, 6);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([1, 2, 3, undefined, undefined, 6]);\n    });\n  });\n\n  describe('update()', () => {\n    it('should replace all items that matches the predicate and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { update }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        update((a, _) => a % 2 === 1, 0);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([0, 2, 0]);\n    });\n\n    it('should pass two parameters to the predicate, iterated element and new one', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { update }]] = hook.result.current;\n      const spy = jest.fn();\n\n      act(() => {\n        update(spy, 0);\n      });\n\n      expect(spy.mock.calls[0][0]).toBe(1);\n      expect(spy.mock.calls[0][1]).toBe(0);\n    });\n  });\n\n  describe('updateFirst()', () => {\n    it('should replace first items that matches the predicate and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { updateFirst }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        updateFirst((a, _) => a % 2 === 1, 0);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([0, 2, 3]);\n    });\n\n    it('should pass two parameters to the predicate, iterated element and new one', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { updateFirst }]] = hook.result.current;\n      const spy = jest.fn();\n\n      act(() => {\n        updateFirst(spy, 0);\n      });\n\n      expect(spy.mock.calls[0].length).toBe(2);\n      expect(spy.mock.calls[0][0]).toBe(1);\n      expect(spy.mock.calls[0][1]).toBe(0);\n    });\n  });\n\n  describe('upsert()', () => {\n    it('should replace first item that matches the predicate and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { upsert }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        upsert((a, _) => a === 1, 0);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([0, 2, 3]);\n    });\n\n    it('otherwise should push it to the list and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { upsert }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        upsert((a, _) => a === 5, 0);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([1, 2, 3, 0]);\n    });\n\n    it('should pass two parameters to the predicate, iterated element and new one', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { upsert }]] = hook.result.current;\n      const spy = jest.fn();\n\n      act(() => {\n        upsert(spy, 0);\n      });\n\n      expect(spy.mock.calls[0].length).toBe(2);\n      expect(spy.mock.calls[0][0]).toBe(1);\n      expect(spy.mock.calls[0][1]).toBe(0);\n    });\n  });\n\n  describe('sort()', () => {\n    it('should sort the list with given comparator and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { sort }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        sort((a, b) => (a === b ? 0 : a < b ? 1 : -1));\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([3, 2, 1]);\n    });\n\n    it('should use default array`s sorting function of called without parameters', () => {\n      const hook = getHook([2, 3, 1]);\n      const [, [, { sort }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        sort();\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([1, 2, 3]);\n    });\n  });\n\n  describe('filter()', () => {\n    it('should filter the list with given predicate and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { filter }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        filter((val) => val % 2 === 1);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([1, 3]);\n    });\n\n    it('should pass three parameters to the predicate, iterated element, it`s index and filtered array', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [list, { filter }]] = hook.result.current;\n      const spy = jest.fn((_, _2, _3) => false);\n\n      act(() => {\n        filter(spy);\n      });\n\n      expect(spy.mock.calls[0].length).toBe(3);\n      expect(spy.mock.calls[0][0]).toBe(1);\n      expect(spy.mock.calls[0][1]).toBe(0);\n      expect(spy.mock.calls[0][2]).toEqual(list);\n    });\n  });\n\n  describe('removeAt()', () => {\n    it('should remove item at given index and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { removeAt }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        removeAt(1);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([1, 3]);\n    });\n\n    it('should do nothing if index is out of array length, although it should cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { removeAt }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        removeAt(5);\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([1, 2, 3]);\n    });\n  });\n\n  describe('remove()', () => {\n    it('should be a ref to removeAt', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { remove, removeAt }]] = hook.result.current;\n\n      expect(remove).toBe(removeAt);\n    });\n  });\n\n  describe('clear()', () => {\n    it('should clear the list and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { clear }]] = hook.result.current;\n\n      expect(hook.result.current[0]).toBe(1);\n      act(() => {\n        clear();\n      });\n      expect(hook.result.current[0]).toBe(2);\n      expect(hook.result.current[1][0]).toEqual([]);\n    });\n  });\n\n  describe('reset()', () => {\n    it('should reset list to initial values and cause re-render', () => {\n      const hook = getHook([1, 2, 3]);\n      const [, [, { set, reset }]] = hook.result.current;\n\n      act(() => {\n        set([1, 2, 3, 4, 6, 7, 8]);\n      });\n      expect(hook.result.current[1][0]).toEqual([1, 2, 3, 4, 6, 7, 8]);\n\n      expect(hook.result.current[0]).toBe(2);\n      act(() => {\n        reset();\n      });\n      expect(hook.result.current[0]).toBe(3);\n      expect(hook.result.current[1][0]).toEqual([1, 2, 3]);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/useLocalStorage.test.ts",
    "content": "import useLocalStorage from '../src/useLocalStorage';\nimport 'jest-localstorage-mock';\nimport { renderHook, act } from '@testing-library/react-hooks';\n\ndescribe(useLocalStorage, () => {\n  afterEach(() => {\n    localStorage.clear();\n    jest.clearAllMocks();\n  });\n\n  it('retrieves an existing value from localStorage', () => {\n    localStorage.setItem('foo', '\"bar\"');\n    const { result } = renderHook(() => useLocalStorage('foo'));\n    const [state] = result.current;\n    expect(state).toEqual('bar');\n  });\n\n  it('should return initialValue if localStorage empty and set that to localStorage', () => {\n    const { result } = renderHook(() => useLocalStorage('foo', 'bar'));\n    const [state] = result.current;\n    expect(state).toEqual('bar');\n    expect(localStorage.__STORE__.foo).toEqual('\"bar\"');\n  });\n\n  it('prefers existing value over initial state', () => {\n    localStorage.setItem('foo', '\"bar\"');\n    const { result } = renderHook(() => useLocalStorage('foo', 'baz'));\n    const [state] = result.current;\n    expect(state).toEqual('bar');\n  });\n\n  it('does not clobber existing localStorage with initialState', () => {\n    localStorage.setItem('foo', '\"bar\"');\n    const { result } = renderHook(() => useLocalStorage('foo', 'buzz'));\n    expect(result.current).toBeTruthy();\n    expect(localStorage.__STORE__.foo).toEqual('\"bar\"');\n  });\n\n  it('correctly updates localStorage', () => {\n    const { result, rerender } = renderHook(() => useLocalStorage('foo', 'bar'));\n\n    const [, setFoo] = result.current;\n    act(() => setFoo('baz'));\n    rerender();\n\n    expect(localStorage.__STORE__.foo).toEqual('\"baz\"');\n  });\n\n  it('should return undefined if no initialValue provided and localStorage empty', () => {\n    const { result } = renderHook(() => useLocalStorage('some_key'));\n\n    expect(result.current[0]).toBeUndefined();\n  });\n\n  it('returns and allows null setting', () => {\n    localStorage.setItem('foo', 'null');\n    const { result, rerender } = renderHook(() => useLocalStorage('foo'));\n    const [foo1, setFoo] = result.current;\n    act(() => setFoo(null));\n    rerender();\n\n    const [foo2] = result.current;\n    expect(foo1).toEqual(null);\n    expect(foo2).toEqual(null);\n  });\n\n  it('sets initialState if initialState is an object', () => {\n    renderHook(() => useLocalStorage('foo', { bar: true }));\n    expect(localStorage.__STORE__.foo).toEqual('{\"bar\":true}');\n  });\n\n  it('correctly and promptly returns a new value', () => {\n    const { result, rerender } = renderHook(() => useLocalStorage('foo', 'bar'));\n\n    const [, setFoo] = result.current;\n    act(() => setFoo('baz'));\n    rerender();\n\n    const [foo] = result.current;\n    expect(foo).toEqual('baz');\n  });\n\n  it('reinitializes state when key changes', () => {\n    let key = 'foo';\n    const { result, rerender } = renderHook(() => useLocalStorage(key, 'bar'));\n\n    const [, setState] = result.current;\n    act(() => setState('baz'));\n    key = 'bar';\n    rerender();\n\n    const [state] = result.current;\n    expect(state).toEqual('bar');\n  });\n\n  /*\n  it('keeps multiple hooks accessing the same key in sync', () => {\n    localStorage.setItem('foo', 'bar');\n    const { result: r1, rerender: rerender1 } = renderHook(() => useLocalStorage('foo'));\n    const { result: r2, rerender: rerender2 } = renderHook(() => useLocalStorage('foo'));\n\n    const [, setFoo] = r1.current;\n    act(() => setFoo('potato'));\n    rerender1();\n    rerender2();\n\n    const [val1] = r1.current;\n    const [val2] = r2.current;\n\n    expect(val1).toEqual(val2);\n    expect(val1).toEqual('potato');\n    expect(val2).toEqual('potato');\n  });\n  */\n\n  it('parses out objects from localStorage', () => {\n    localStorage.setItem('foo', JSON.stringify({ ok: true }));\n    const { result } = renderHook(() => useLocalStorage<{ ok: boolean }>('foo'));\n    const [foo] = result.current;\n    expect(foo!.ok).toEqual(true);\n  });\n\n  it('safely initializes objects to localStorage', () => {\n    const { result } = renderHook(() => useLocalStorage<{ ok: boolean }>('foo', { ok: true }));\n    const [foo] = result.current;\n    expect(foo!.ok).toEqual(true);\n  });\n\n  it('safely sets objects to localStorage', () => {\n    const { result, rerender } = renderHook(() =>\n      useLocalStorage<{ ok: any }>('foo', { ok: true })\n    );\n\n    const [, setFoo] = result.current;\n    act(() => setFoo({ ok: 'bar' }));\n    rerender();\n\n    const [foo] = result.current;\n    expect(foo!.ok).toEqual('bar');\n  });\n\n  it('safely returns objects from updates', () => {\n    const { result, rerender } = renderHook(() =>\n      useLocalStorage<{ ok: any }>('foo', { ok: true })\n    );\n\n    const [, setFoo] = result.current;\n    act(() => setFoo({ ok: 'bar' }));\n    rerender();\n\n    const [foo] = result.current;\n    expect(foo).toBeInstanceOf(Object);\n    expect(foo!.ok).toEqual('bar');\n  });\n\n  it('sets localStorage from the function updater', () => {\n    const { result, rerender } = renderHook(() =>\n      useLocalStorage<{ foo: string; fizz?: string }>('foo', { foo: 'bar' })\n    );\n\n    const [, setFoo] = result.current;\n    act(() => setFoo((state) => ({ ...state!, fizz: 'buzz' })));\n    rerender();\n\n    const [value] = result.current;\n    expect(value!.foo).toEqual('bar');\n    expect(value!.fizz).toEqual('buzz');\n  });\n\n  it('rejects nullish or undefined keys', () => {\n    const { result } = renderHook(() => useLocalStorage(null as any));\n    try {\n      (() => {\n        return result.current;\n      })();\n      fail('hook should have thrown');\n    } catch (e) {\n      expect(String(e)).toMatch(/key may not be/i);\n    }\n  });\n\n  /* Enforces proper eslint react-hooks/rules-of-hooks usage */\n  describe('eslint react-hooks/rules-of-hooks', () => {\n    it('memoizes an object between rerenders', () => {\n      const { result, rerender } = renderHook(() => useLocalStorage('foo', { ok: true }));\n      (() => {\n        return result.current; // if localStorage isn't set then r1 and r2 will be different\n      })();\n      rerender();\n      const [r2] = result.current;\n      rerender();\n      const [r3] = result.current;\n      expect(r2).toBe(r3);\n    });\n\n    it('memoizes an object immediately if localStorage is already set', () => {\n      localStorage.setItem('foo', JSON.stringify({ ok: true }));\n      const { result, rerender } = renderHook(() => useLocalStorage('foo', { ok: true }));\n\n      const [r1] = result.current; // if localStorage isn't set then r1 and r2 will be different\n      rerender();\n      const [r2] = result.current;\n      expect(r1).toBe(r2);\n    });\n\n    it('memoizes the setState function', () => {\n      localStorage.setItem('foo', JSON.stringify({ ok: true }));\n      const { result, rerender } = renderHook(() => useLocalStorage('foo', { ok: true }));\n      const [, s1] = result.current;\n      rerender();\n      const [, s2] = result.current;\n      expect(s1).toBe(s2);\n    });\n  });\n\n  describe('Options: raw', () => {\n    it('returns a string when localStorage is a stringified object', () => {\n      localStorage.setItem('foo', JSON.stringify({ fizz: 'buzz' }));\n      const { result } = renderHook(() => useLocalStorage('foo', null, { raw: true }));\n      const [foo] = result.current;\n      expect(typeof foo).toBe('string');\n    });\n\n    it('returns a string after an update', () => {\n      localStorage.setItem('foo', JSON.stringify({ fizz: 'buzz' }));\n      const { result, rerender } = renderHook(() => useLocalStorage('foo', null, { raw: true }));\n\n      const [, setFoo] = result.current;\n\n      act(() => setFoo({ fizz: 'bang' } as any));\n      rerender();\n\n      const [foo] = result.current;\n      expect(typeof foo).toBe('string');\n\n      expect(JSON.parse(foo!)).toBeInstanceOf(Object);\n\n      // expect(JSON.parse(foo!).fizz).toEqual('bang');\n    });\n\n    it('still forces setState to a string', () => {\n      localStorage.setItem('foo', JSON.stringify({ fizz: 'buzz' }));\n      const { result, rerender } = renderHook(() => useLocalStorage('foo', null, { raw: true }));\n\n      const [, setFoo] = result.current;\n\n      act(() => setFoo({ fizz: 'bang' } as any));\n      rerender();\n\n      const [value] = result.current;\n\n      expect(JSON.parse(value!).fizz).toEqual('bang');\n    });\n  });\n});\n"
  },
  {
    "path": "tests/useLogger.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport useLogger from '../src/useLogger';\n\nconst logSpy = jest.spyOn(global.console, 'log').mockImplementation(() => {});\n\ndescribe('useLogger', () => {\n  it('should be defined', () => {\n    expect(useLogger).toBeDefined();\n  });\n\n  it('should log the provided props on mount', () => {\n    const props = { question: 'What is the meaning?', answer: 42 };\n    renderHook(() => useLogger('Test', props));\n\n    expect(logSpy).toBeCalledTimes(1);\n    expect(logSpy).toHaveBeenLastCalledWith('Test mounted', props);\n  });\n\n  it('should log when the component has unmounted', () => {\n    const props = { question: 'What is the meaning?', answer: 42 };\n    const { unmount } = renderHook(() => useLogger('Test', props));\n\n    unmount();\n\n    expect(logSpy).toHaveBeenLastCalledWith('Test unmounted');\n  });\n\n  it('should log updates as props change', () => {\n    const { rerender } = renderHook(\n      ({ componentName, props }: { componentName: string; props: any }) =>\n        useLogger(componentName, props),\n      {\n        initialProps: { componentName: 'Test', props: { one: 1 } },\n      }\n    );\n\n    const newProps = { one: 1, two: 2 };\n    rerender({ componentName: 'Test', props: newProps });\n\n    expect(logSpy).toHaveBeenLastCalledWith('Test updated', newProps);\n  });\n});\n"
  },
  {
    "path": "tests/useLongPress.test.tsx",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport useLongPress from '../src/useLongPress';\n\nconst callback = jest.fn();\nconst defaultDelay = 300;\nconst mouseDown = new MouseEvent('mousedown');\nconst touchStart = new TouchEvent('touchstart');\n\nbeforeAll(() => {\n  jest.useFakeTimers();\n});\n\nafterEach(() => {\n  callback.mockRestore();\n  jest.clearAllTimers();\n});\n\nafterAll(() => {\n  jest.useRealTimers();\n});\n\nit('should not call provided callback without trigger any event', () => {\n  renderHook(() => useLongPress(callback));\n\n  expect(callback).toHaveBeenCalledTimes(0);\n\n  jest.advanceTimersByTime(defaultDelay);\n\n  expect(callback).toHaveBeenCalledTimes(0);\n});\n\nit('should call provided callback onMouseDown', () => {\n  const { result } = renderHook(() => useLongPress(callback));\n  const { onMouseDown } = result.current;\n\n  expect(callback).toHaveBeenCalledTimes(0);\n  onMouseDown(mouseDown);\n\n  jest.advanceTimersByTime(defaultDelay - 20);\n  expect(callback).toHaveBeenCalledTimes(0);\n\n  jest.advanceTimersByTime(20);\n  expect(callback).toHaveBeenCalledTimes(1);\n});\n\nit('should call provided callback with custom delay', () => {\n  const customDelay = 1000;\n  const { result } = renderHook(() => useLongPress(callback, { delay: customDelay }));\n  const { onMouseDown } = result.current;\n\n  expect(callback).toHaveBeenCalledTimes(0);\n  onMouseDown(mouseDown);\n\n  jest.advanceTimersByTime(customDelay - 20);\n  expect(callback).toHaveBeenCalledTimes(0);\n\n  jest.advanceTimersByTime(20);\n  expect(callback).toHaveBeenCalledTimes(1);\n});\n\nit('should not call provided callback if interrupted by onMouseLeave', () => {\n  const { result } = renderHook(() => useLongPress(callback));\n  const { onMouseDown, onMouseLeave } = result.current;\n\n  expect(callback).toHaveBeenCalledTimes(0);\n  onMouseDown(mouseDown);\n\n  jest.advanceTimersByTime(defaultDelay - 20);\n  expect(callback).toHaveBeenCalledTimes(0);\n\n  onMouseLeave();\n\n  jest.advanceTimersByTime(20);\n  expect(callback).toHaveBeenCalledTimes(0);\n  expect(setTimeout).toHaveBeenCalledTimes(1);\n});\n\nit('should not call provided callback if interrupted by onMouseUp', () => {\n  const { result } = renderHook(() => useLongPress(callback));\n  const { onMouseDown, onMouseUp } = result.current;\n\n  expect(callback).toHaveBeenCalledTimes(0);\n  onMouseDown(mouseDown);\n\n  jest.advanceTimersByTime(defaultDelay - 20);\n  expect(callback).toHaveBeenCalledTimes(0);\n\n  onMouseUp();\n\n  jest.advanceTimersByTime(20);\n  expect(callback).toHaveBeenCalledTimes(0);\n  expect(setTimeout).toHaveBeenCalledTimes(1);\n});\n\nit('should call provided callback onTouchStart', () => {\n  const { result } = renderHook(() => useLongPress(callback));\n  const { onTouchStart } = result.current;\n\n  expect(callback).toHaveBeenCalledTimes(0);\n  onTouchStart(touchStart);\n\n  jest.advanceTimersByTime(defaultDelay - 20);\n  expect(callback).toHaveBeenCalledTimes(0);\n\n  jest.advanceTimersByTime(20);\n  expect(callback).toHaveBeenCalledTimes(1);\n});\n\nit('should not call provided callback if interrupted by onTouchEnd', () => {\n  const { result } = renderHook(() => useLongPress(callback));\n  const { onTouchStart, onTouchEnd } = result.current;\n\n  expect(callback).toHaveBeenCalledTimes(0);\n  onTouchStart(touchStart);\n\n  jest.advanceTimersByTime(defaultDelay - 20);\n  expect(callback).toHaveBeenCalledTimes(0);\n\n  onTouchEnd();\n\n  jest.advanceTimersByTime(20);\n  expect(callback).toHaveBeenCalledTimes(0);\n  expect(setTimeout).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "tests/useMap.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useMap from '../src/useMap';\n\nconst setUp = <T extends object>(initialMap?: T) => renderHook(() => useMap(initialMap));\n\nit('should init map and utils', () => {\n  const { result } = setUp({ foo: 'bar', a: 1 });\n  const [map, utils] = result.current;\n\n  expect(map).toEqual({ foo: 'bar', a: 1 });\n  expect(utils).toStrictEqual({\n    get: expect.any(Function),\n    set: expect.any(Function),\n    setAll: expect.any(Function),\n    remove: expect.any(Function),\n    reset: expect.any(Function),\n  });\n});\n\nit('should init empty map if not initial object provided', () => {\n  const { result } = setUp();\n\n  expect(result.current[0]).toEqual({});\n});\n\nit('should get corresponding value for initial provided key', () => {\n  const { result } = setUp({ foo: 'bar', a: 1 });\n  const [, utils] = result.current;\n\n  let value;\n  act(() => {\n    value = utils.get('a');\n  });\n\n  expect(value).toBe(1);\n});\n\nit('should get corresponding value for existing provided key', () => {\n  const { result } = setUp({ foo: 'bar', a: 1 });\n\n  act(() => {\n    result.current[1].set('a', 99);\n  });\n\n  let value;\n  act(() => {\n    value = result.current[1].get('a');\n  });\n\n  expect(value).toBe(99);\n});\n\nit('should get undefined for non-existing provided key', () => {\n  const { result } = setUp<{ foo: string; a: number; nonExisting?: any }>({ foo: 'bar', a: 1 });\n  const [, utils] = result.current;\n\n  let value;\n  act(() => {\n    value = utils.get('nonExisting');\n  });\n\n  expect(value).toBeUndefined();\n});\n\nit('should set new key-value pair', () => {\n  const { result } = setUp<{ foo: string; a: number; newKey?: number }>({ foo: 'bar', a: 1 });\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.set('newKey', 99);\n  });\n\n  expect(result.current[0]).toEqual({ foo: 'bar', a: 1, newKey: 99 });\n});\n\nit('should override current value if setting existing key', () => {\n  const { result } = setUp({ foo: 'bar', a: 1 });\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.set('foo', 'qux');\n  });\n\n  expect(result.current[0]).toEqual({ foo: 'qux', a: 1 });\n});\n\nit('should set new map', () => {\n  const { result } = setUp<{ foo: string; a: number; newKey?: number }>({ foo: 'bar', a: 1 });\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.setAll({ foo: 'foo', a: 2 });\n  });\n\n  expect(result.current[0]).toEqual({ foo: 'foo', a: 2 });\n});\n\nit('should remove corresponding key-value pair for existing provided key', () => {\n  const { result } = setUp({ foo: 'bar', a: 1 });\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.remove('foo');\n  });\n\n  expect(result.current[0]).toEqual({ a: 1 });\n});\n\nit('should do nothing if removing non-existing provided key', () => {\n  const { result } = setUp<{ foo: string; a: number; nonExisting?: any }>({ foo: 'bar', a: 1 });\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.remove('nonExisting');\n  });\n\n  expect(result.current[0]).toEqual({ foo: 'bar', a: 1 });\n});\n\nit('should reset map to initial object provided', () => {\n  const { result } = setUp<{ foo: string; a: number; z?: number }>({ foo: 'bar', a: 1 });\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.set('z', 99);\n  });\n\n  expect(result.current[0]).toEqual({ foo: 'bar', a: 1, z: 99 });\n\n  act(() => {\n    utils.reset();\n  });\n\n  expect(result.current[0]).toEqual({ foo: 'bar', a: 1 });\n});\n\nit('should memoize actions with side effects', () => {\n  const { result } = setUp({ foo: 'bar', a: 1 });\n  const [, utils] = result.current;\n  const { set, remove, reset } = utils;\n\n  act(() => {\n    set('foo', 'baz');\n  });\n\n  expect(result.current[1].set).toBe(set);\n  expect(result.current[1].remove).toBe(remove);\n  expect(result.current[1].reset).toBe(reset);\n});\n"
  },
  {
    "path": "tests/useMeasure.test.ts",
    "content": "import { renderHook, act } from '@testing-library/react-hooks';\nimport useMeasure, { UseMeasureRef } from '../src/useMeasure';\n\nit('by default, state defaults every value to -1', () => {\n  const { result } = renderHook(() => useMeasure());\n\n  act(() => {\n    const div = document.createElement('div');\n    (result.current[0] as UseMeasureRef)(div);\n  });\n\n  expect(result.current[1]).toMatchObject({\n    width: 0,\n    height: 0,\n    top: 0,\n    bottom: 0,\n    left: 0,\n    right: 0,\n  });\n});\n\nit('synchronously sets up ResizeObserver listener', () => {\n  let listener: ((rect: any) => void) | undefined = undefined;\n  (window as any).ResizeObserver = class ResizeObserver {\n    constructor(ls) {\n      listener = ls;\n    }\n    observe() {}\n    disconnect() {}\n  };\n\n  const { result } = renderHook(() => useMeasure());\n\n  act(() => {\n    const div = document.createElement('div');\n    (result.current[0] as UseMeasureRef)(div);\n  });\n\n  expect(typeof listener).toBe('function');\n});\n\nit('tracks rectangle of a DOM element', () => {\n  let listener: ((rect: any) => void) | undefined = undefined;\n  (window as any).ResizeObserver = class ResizeObserver {\n    constructor(ls) {\n      listener = ls;\n    }\n    observe() {}\n    disconnect() {}\n  };\n\n  const { result } = renderHook(() => useMeasure());\n\n  act(() => {\n    const div = document.createElement('div');\n    (result.current[0] as UseMeasureRef)(div);\n  });\n\n  act(() => {\n    listener!([\n      {\n        contentRect: {\n          x: 1,\n          y: 2,\n          width: 200,\n          height: 200,\n          top: 100,\n          bottom: 0,\n          left: 100,\n          right: 0,\n        },\n      },\n    ]);\n  });\n\n  expect(result.current[1]).toMatchObject({\n    x: 1,\n    y: 2,\n    width: 200,\n    height: 200,\n    top: 100,\n    bottom: 0,\n    left: 100,\n    right: 0,\n  });\n});\n\nit('tracks multiple updates', () => {\n  let listener: ((rect: any) => void) | undefined = undefined;\n  (window as any).ResizeObserver = class ResizeObserver {\n    constructor(ls) {\n      listener = ls;\n    }\n    observe() {}\n    disconnect() {}\n  };\n\n  const { result } = renderHook(() => useMeasure());\n\n  act(() => {\n    const div = document.createElement('div');\n    (result.current[0] as UseMeasureRef)(div);\n  });\n\n  act(() => {\n    listener!([\n      {\n        contentRect: {\n          x: 1,\n          y: 1,\n          width: 1,\n          height: 1,\n          top: 1,\n          bottom: 1,\n          left: 1,\n          right: 1,\n        },\n      },\n    ]);\n  });\n\n  expect(result.current[1]).toMatchObject({\n    x: 1,\n    y: 1,\n    width: 1,\n    height: 1,\n    top: 1,\n    bottom: 1,\n    left: 1,\n    right: 1,\n  });\n\n  act(() => {\n    listener!([\n      {\n        contentRect: {\n          x: 2,\n          y: 2,\n          width: 2,\n          height: 2,\n          top: 2,\n          bottom: 2,\n          left: 2,\n          right: 2,\n        },\n      },\n    ]);\n  });\n\n  expect(result.current[1]).toMatchObject({\n    x: 2,\n    y: 2,\n    width: 2,\n    height: 2,\n    top: 2,\n    bottom: 2,\n    left: 2,\n    right: 2,\n  });\n});\n\nit('calls .disconnect() on ResizeObserver when component unmounts', () => {\n  const disconnect = jest.fn();\n  (window as any).ResizeObserver = class ResizeObserver {\n    observe() {}\n    disconnect() {\n      disconnect();\n    }\n  };\n\n  const { result, unmount } = renderHook(() => useMeasure());\n\n  act(() => {\n    const div = document.createElement('div');\n    (result.current[0] as UseMeasureRef)(div);\n  });\n\n  expect(disconnect).toHaveBeenCalledTimes(0);\n\n  unmount();\n\n  expect(disconnect).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "tests/useMedia.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { renderHook as renderHookSSR } from '@testing-library/react-hooks/server';\nimport { useMedia } from '../src';\n\nconst createMockMediaMatcher = (matches: Record<string, boolean>) => (qs: string) => ({\n  matches: matches[qs] ?? false,\n  addEventListener: () => {},\n  removeEventListener: () => {},\n});\n\ndescribe('useMedia', () => {\n  beforeEach(() => {\n    window.matchMedia = createMockMediaMatcher({\n      '(min-width: 500px)': true,\n      '(min-width: 1000px)': false,\n    }) as any;\n  });\n  it('should return true if media query matches', () => {\n    const { result } = renderHook(() => useMedia('(min-width: 500px)'));\n    expect(result.current).toBe(true);\n  });\n  it('should return false if media query does not match', () => {\n    const { result } = renderHook(() => useMedia('(min-width: 1200px)'));\n    expect(result.current).toBe(false);\n  });\n  it('should return default state before hydration', () => {\n    const { result } = renderHookSSR(() => useMedia('(min-width: 500px)', false));\n    expect(result.current).toBe(false);\n  });\n  it('should return media query result after hydration', async () => {\n    const { result, hydrate } = renderHookSSR(() => useMedia('(min-width: 500px)', false));\n    expect(result.current).toBe(false);\n    hydrate();\n    expect(result.current).toBe(true);\n  });\n  it('should return media query result after hydration', async () => {\n    const { result, hydrate } = renderHookSSR(() => useMedia('(min-width: 1200px)', true));\n    expect(result.current).toBe(true);\n    hydrate();\n    expect(result.current).toBe(false);\n  });\n});\n"
  },
  {
    "path": "tests/useMediatedState.test.ts",
    "content": "import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks';\nimport { Dispatch, SetStateAction } from 'react';\nimport { useMediatedState } from '../src';\nimport { StateMediator, UseMediatedStateReturn } from '../src/useMediatedState';\n\ndescribe('useMediatedState', () => {\n  it('should be defined', () => {\n    expect(useMediatedState).toBeDefined();\n  });\n\n  function getHook(\n    initialState: number = 2,\n    fn: StateMediator<number> = jest.fn((newState) => newState / 2)\n  ): [jest.Mock | StateMediator, RenderHookResult<any, UseMediatedStateReturn<number>>] {\n    return [fn, renderHook(() => useMediatedState<number>(fn, initialState))];\n  }\n\n  it('should return array of two elements', () => {\n    const [, hook] = getHook();\n\n    expect(Array.isArray(hook.result.current)).toBe(true);\n    expect(hook.result.current[0]).toBe(2);\n    expect(typeof hook.result.current[1]).toBe('function');\n  });\n\n  it('should act like regular useState but with mediator call on each setState', () => {\n    const [spy, hook] = getHook();\n\n    expect(hook.result.current[0]).toBe(2);\n\n    act(() => hook.result.current[1](3));\n    expect(hook.result.current[0]).toBe(1.5);\n    expect(spy).toHaveBeenCalledTimes(1);\n\n    act(() => hook.result.current[1](4));\n    expect(hook.result.current[0]).toBe(2);\n    expect(spy).toHaveBeenCalledTimes(2);\n  });\n\n  it('should not call mediator on init', () => {\n    const [spy] = getHook();\n\n    expect(spy).toHaveBeenCalledTimes(0);\n  });\n\n  it('mediator should receive setState argument as first argument', () => {\n    let val;\n    const spy = jest.fn((newState) => {\n      val = newState;\n      return newState * 2;\n    });\n    const [, hook] = getHook(1, spy);\n\n    act(() => hook.result.current[1](3));\n    expect(val).toBe(3);\n    expect(hook.result.current[0]).toBe(6);\n  });\n\n  it('if mediator expects 2 args, second should be a function setting the state', () => {\n    const spy = jest.fn((newState: number, setState: Dispatch<SetStateAction<number>>): void => {\n      setState(newState * 2);\n    }) as unknown as StateMediator<number>;\n    const [, hook] = getHook(1, spy);\n\n    act(() => hook.result.current[1](3));\n    expect(hook.result.current[0]).toBe(6);\n  });\n});\n"
  },
  {
    "path": "tests/useMethods.test.ts",
    "content": "import { renderHook, act } from '@testing-library/react-hooks';\nimport { useMethods } from '../src';\n\nit('should have initialState value as the returned state value', () => {\n  const initialState = {\n    count: 10,\n  };\n\n  const createMethods = (state) => ({\n    doStuff: () => state,\n  });\n\n  const { result } = renderHook(() => useMethods(createMethods, initialState));\n\n  expect(result.current[0]).toEqual(initialState);\n});\n\nit('should return wrappedMethods object containing all the methods defined in createMethods', () => {\n  const initialState = {\n    count: 10,\n  };\n\n  const createMethods = (state) => ({\n    reset() {\n      return initialState;\n    },\n    increment() {\n      return { ...state, count: state.count + 1 };\n    },\n    decrement() {\n      return { ...state, count: state.count - 1 };\n    },\n  });\n\n  const { result } = renderHook(() => useMethods(createMethods, initialState));\n\n  for (const key of Object.keys(createMethods(initialState))) {\n    expect(result.current[1][key]).toBeDefined();\n  }\n});\n\nit('should properly update the state based on the createMethods', () => {\n  const count = 10;\n  const initialState = {\n    count,\n  };\n\n  const createMethods = (state) => ({\n    reset() {\n      return initialState;\n    },\n    increment() {\n      return { ...state, count: state.count + 1 };\n    },\n    decrement() {\n      return { ...state, count: state.count - 1 };\n    },\n  });\n\n  const { result } = renderHook(() => useMethods(createMethods, initialState));\n\n  act(() => {\n    result.current[1].increment();\n  });\n  expect(result.current[0].count).toBe(count + 1);\n\n  act(() => {\n    result.current[1].decrement();\n  });\n  expect(result.current[0].count).toBe(count);\n\n  act(() => {\n    result.current[1].decrement();\n  });\n  expect(result.current[0].count).toBe(count - 1);\n\n  act(() => {\n    result.current[1].reset();\n  });\n  expect(result.current[0].count).toBe(count);\n});\n"
  },
  {
    "path": "tests/useMount.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useMount } from '../src';\n\nconst mockCallback = jest.fn();\n\nafterEach(() => {\n  jest.resetAllMocks();\n});\n\nit('should call provided callback on mount', () => {\n  renderHook(() => useMount(mockCallback));\n\n  expect(mockCallback).toHaveBeenCalledTimes(1);\n});\n\nit('should not call provided callback on unmount', () => {\n  const { unmount } = renderHook(() => useMount(mockCallback));\n  expect(mockCallback).toHaveBeenCalledTimes(1);\n\n  unmount();\n\n  expect(mockCallback).toHaveBeenCalledTimes(1);\n});\n\nit('should not call provided callback on rerender', () => {\n  const { rerender } = renderHook(() => useMount(mockCallback));\n  expect(mockCallback).toHaveBeenCalledTimes(1);\n\n  rerender();\n\n  expect(mockCallback).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "tests/useMountedState.test.tsx",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport useMountedState from '../src/useMountedState';\n\ndescribe('useMountedState', () => {\n  it('should be defined', () => {\n    expect(useMountedState).toBeDefined();\n  });\n\n  it('should return a function', () => {\n    const hook = renderHook(() => useMountedState(), { initialProps: false });\n\n    expect(typeof hook.result.current).toEqual('function');\n  });\n\n  it('should return true if component is mounted', () => {\n    const hook = renderHook(() => useMountedState(), { initialProps: false });\n\n    expect(hook.result.current()).toBeTruthy();\n  });\n\n  it('should return false if component is unmounted', () => {\n    const hook = renderHook(() => useMountedState(), { initialProps: false });\n\n    hook.unmount();\n\n    expect(hook.result.current()).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "tests/useMultiStateValidator.test.ts",
    "content": "import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks';\nimport { useState } from 'react';\nimport { MultiStateValidator, useMultiStateValidator } from '../src/useMultiStateValidator';\nimport { UseStateValidatorReturn, ValidityState } from '../src/useStateValidator';\n\ninterface Mock extends jest.Mock {}\n\ndescribe('useMultiStateValidator', () => {\n  it('should be defined', () => {\n    expect(useMultiStateValidator).toBeDefined();\n  });\n\n  const defaultStatesValidator = (states: number[]) => [states.every((num) => !(num % 2))];\n\n  function getHook(\n    fn: MultiStateValidator<any, number[]> = jest.fn(defaultStatesValidator),\n    initialStates = [1, 2],\n    initialValidity = [false]\n  ): [\n    MultiStateValidator<any, number[]>,\n    RenderHookResult<any, [Function, UseStateValidatorReturn<ValidityState>]>\n  ] {\n    return [\n      fn,\n      renderHook(\n        ({ initStates, validator, initValidity }) => {\n          const [states, setStates] = useState(initStates);\n\n          return [setStates, useMultiStateValidator(states, validator, initValidity)];\n        },\n        {\n          initialProps: {\n            initStates: initialStates,\n            initValidity: initialValidity,\n            validator: fn,\n          },\n        }\n      ),\n    ];\n  }\n\n  it('should return an array of two elements', () => {\n    const [, hook] = getHook();\n    const res = hook.result.current[1];\n\n    expect(Array.isArray(res)).toBe(true);\n    expect(res.length).toBe(2);\n  });\n\n  it('should call validator on init', () => {\n    const [spy] = getHook();\n\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n\n  it('should call validator on any of states changed', () => {\n    const [spy, hook] = getHook();\n\n    expect(spy).toHaveBeenCalledTimes(1);\n    act(() => hook.result.current[0]([4, 2]));\n    expect(spy).toHaveBeenCalledTimes(2);\n  });\n\n  it(\"should NOT call validator on it's change\", () => {\n    const [spy, hook] = getHook();\n    const newValidator: MultiStateValidator<any, number[]> = jest.fn((states) => [\n      states!.every((num) => !!(num % 2)),\n    ]);\n\n    expect(spy).toHaveBeenCalledTimes(1);\n    hook.rerender({ validator: newValidator });\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n\n  it('should throw if states is not an object', () => {\n    expect(() => {\n      // @ts-ignore\n      const [, hook] = getHook(defaultStatesValidator, 123);\n\n      if (hook.result.error) {\n        throw hook.result.error;\n      }\n    }).toThrowError('states expected to be an object or array, got number');\n  });\n\n  it('first returned element should represent current validity state', () => {\n    const [, hook] = getHook();\n    let [setState, [validity]] = hook.result.current;\n    expect(validity).toEqual([false]);\n\n    act(() => setState([4, 2]));\n    [setState, [validity]] = hook.result.current;\n    expect(validity).toEqual([true]);\n\n    act(() => setState([4, 5]));\n    [setState, [validity]] = hook.result.current;\n    expect(validity).toEqual([false]);\n  });\n\n  it('second returned element should re-call validation', () => {\n    const [spy, hook] = getHook();\n    const [, [, revalidate]] = hook.result.current;\n\n    expect(spy).toHaveBeenCalledTimes(1);\n    act(() => revalidate());\n    expect(spy).toHaveBeenCalledTimes(2);\n  });\n\n  it('validator should receive states as a firs argument', () => {\n    const [spy, hook] = getHook();\n    const [setState] = hook.result.current;\n\n    expect((spy as Mock).mock.calls[0].length).toBe(1);\n    expect((spy as Mock).mock.calls[0][0]).toEqual([1, 2]);\n    act(() => setState([4, 6]));\n    expect((spy as Mock).mock.calls[1][0]).toEqual([4, 6]);\n  });\n\n  it('if validator expects 2nd parameters it should pass a validity setter there', () => {\n    const spy = jest.fn((states: number[], done) => {\n      done([states.every((num) => !!(num % 2))]);\n    }) as unknown as MultiStateValidator<[boolean], number[]>;\n    const [, hook] = getHook(spy, [1, 3]);\n    const [, [validity]] = hook.result.current;\n\n    expect((spy as Mock).mock.calls[0].length).toBe(2);\n    expect((spy as Mock).mock.calls[0][0]).toEqual([1, 3]);\n    expect(validity).toEqual([true]);\n  });\n});\n"
  },
  {
    "path": "tests/useNetworkState.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useNetworkState } from '../src';\n\n//ToDo: improve tests\ndescribe(`useNetworkState`, () => {\n  it('should be defined', () => {\n    expect(useNetworkState).toBeDefined();\n  });\n\n  it('should return an object of certain structure', () => {\n    const hook = renderHook(() => useNetworkState(), { initialProps: false });\n\n    expect(typeof hook.result.current).toEqual('object');\n    expect(Object.keys(hook.result.current)).toEqual([\n      'online',\n      'previous',\n      'since',\n      'downlink',\n      'downlinkMax',\n      'effectiveType',\n      'rtt',\n      'saveData',\n      'type',\n    ]);\n  });\n});\n"
  },
  {
    "path": "tests/useNumber.test.ts",
    "content": "import useCounter from '../src/useCounter';\nimport useNumber from '../src/useNumber';\n\nit('should be an alias for useCounter', () => {\n  expect(useNumber).toBe(useCounter);\n});\n"
  },
  {
    "path": "tests/useObservable.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport { Subject } from 'rxjs';\nimport * as useIsomorphicLayoutEffect from '../src/useIsomorphicLayoutEffect';\nimport useObservable, { Observable } from '../src/useObservable';\n\nconst setUp = (observable: Observable<any>, initialValue?: any) =>\n  renderHook(() => useObservable(observable, initialValue));\n\nit('should init to initial value provided', () => {\n  const subject$ = new Subject();\n  const { result } = setUp(subject$, 123);\n\n  expect(result.current).toBe(123);\n});\n\nit('should init to undefined if not initial value provided', () => {\n  const subject$ = new Subject();\n  const { result } = setUp(subject$);\n\n  expect(result.current).toBeUndefined();\n});\n\nit('should return latest value of observables', () => {\n  const subject$ = new Subject();\n  const { result } = setUp(subject$, 123);\n\n  act(() => {\n    subject$.next(125);\n  });\n  expect(result.current).toBe(125);\n\n  act(() => {\n    subject$.next(300);\n    subject$.next(400);\n  });\n  expect(result.current).toBe(400);\n});\n\nit('should use layout effect to subscribe synchronously', async () => {\n  const subject$ = new Subject();\n  const spy = jest.spyOn(useIsomorphicLayoutEffect, 'default');\n\n  expect(spy).toHaveBeenCalledTimes(0);\n\n  setUp(subject$, 123);\n\n  expect(spy).toHaveBeenCalledTimes(1);\n});\n\nit('should subscribe to observable only once', () => {\n  const subject$ = new Subject();\n  const spy = jest.spyOn(subject$, 'subscribe');\n  expect(spy).not.toHaveBeenCalled();\n\n  setUp(subject$, 123);\n\n  expect(spy).toHaveBeenCalledTimes(1);\n\n  act(() => {\n    subject$.next('a');\n  });\n\n  act(() => {\n    subject$.next('b');\n  });\n\n  expect(spy).toHaveBeenCalledTimes(1);\n});\n\nit('should return updated value when observable changes', () => {\n  const subject$ = new Subject();\n  const { result } = setUp(subject$);\n  expect(result.current).toBeUndefined();\n\n  act(() => {\n    subject$.next('foo');\n  });\n  expect(result.current).toBe('foo');\n\n  act(() => {\n    subject$.next('bar');\n  });\n  expect(result.current).toBe('bar');\n});\n\nit('should unsubscribe from observable', () => {\n  const subject$ = new Subject();\n  const unsubscribeMock = jest.fn();\n  subject$.subscribe = jest.fn().mockReturnValue({\n    unsubscribe: unsubscribeMock,\n  });\n\n  const { unmount } = setUp(subject$);\n  expect(unsubscribeMock).not.toHaveBeenCalled();\n\n  act(() => {\n    subject$.next('foo');\n  });\n  expect(unsubscribeMock).not.toHaveBeenCalled();\n\n  act(() => {\n    subject$.next('bar');\n  });\n  expect(unsubscribeMock).not.toHaveBeenCalled();\n\n  unmount();\n  expect(unsubscribeMock).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "tests/useOrientation.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport { replaceRaf } from 'raf-stub';\nimport useOrientation from '../src/useOrientation';\n\ndeclare var requestAnimationFrame: {\n  reset: () => void;\n  step: (steps?: number, duration?: number) => void;\n};\n\ndescribe('useOrientation', () => {\n  beforeAll(() => {\n    replaceRaf();\n  });\n\n  beforeEach(() => {\n    (window.screen.orientation as object) = {\n      type: 'landscape-primary',\n      angle: 0,\n    };\n    (window.orientation as number) = 0;\n  });\n\n  afterEach(() => {\n    requestAnimationFrame.reset();\n  });\n\n  it('should be defined', () => {\n    expect(useOrientation).toBeDefined();\n  });\n\n  function getHook(...args) {\n    return renderHook(() => useOrientation(...args));\n  }\n\n  function triggerOrientation(type: string, angle: number) {\n    (window.screen.orientation.type as string) = type;\n    (window.screen.orientation.angle as number) = angle;\n\n    window.dispatchEvent(new Event('orientationchange'));\n  }\n\n  it('should return current window orientation', () => {\n    const hook = getHook();\n\n    expect(typeof hook.result.current).toBe('object');\n    expect(typeof hook.result.current.type).toBe('string');\n    expect(typeof hook.result.current.angle).toBe('number');\n  });\n\n  it('should use initial values in case of no parameters', () => {\n    const hook = getHook();\n\n    expect(hook.result.current.type).toBe('landscape-primary');\n    expect(hook.result.current.angle).toBe(0);\n  });\n\n  it('should re-render after orientation change on closest RAF', () => {\n    const hook = getHook();\n\n    act(() => {\n      triggerOrientation('portrait-secondary', 180);\n      requestAnimationFrame.step();\n    });\n\n    expect(hook.result.current.type).toBe('portrait-secondary');\n    expect(hook.result.current.angle).toBe(180);\n  });\n\n  it('should return window.orientation number if window.screen.orientation is missing', () => {\n    (window.screen.orientation as unknown) = undefined;\n\n    const hook = getHook();\n\n    expect(hook.result.current.type).toBe('');\n    expect(hook.result.current.angle).toBe(0);\n  });\n\n  it('should return 0 if window.orientation is not a number and if window.screen.orientation is missing', () => {\n    (window.screen.orientation as unknown) = undefined;\n    (window.orientation as unknown) = null;\n\n    const hook = getHook();\n\n    expect(hook.result.current.type).toBe('');\n    expect(hook.result.current.angle).toBe(0);\n  });\n});\n"
  },
  {
    "path": "tests/usePrevious.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport usePrevious from '../src/usePrevious';\n\nconst setUp = () => renderHook(({ state }) => usePrevious(state), { initialProps: { state: 0 } });\n\nit('should return undefined on initial render', () => {\n  const { result } = setUp();\n\n  expect(result.current).toBeUndefined();\n});\n\nit('should always return previous state after each update', () => {\n  const { result, rerender } = setUp();\n\n  rerender({ state: 2 });\n  expect(result.current).toBe(0);\n\n  rerender({ state: 4 });\n  expect(result.current).toBe(2);\n\n  rerender({ state: 6 });\n  expect(result.current).toBe(4);\n});\n"
  },
  {
    "path": "tests/usePreviousDistinct.test.tsx",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport usePreviousDistinct, { Predicate } from '../src/usePreviousDistinct';\n\ndescribe('usePreviousDistinct', () => {\n  it('should be defined', () => {\n    expect(usePreviousDistinct).toBeDefined();\n  });\n\n  function getHook<T>(initialValue?: T, predicate?: Predicate<T>) {\n    return renderHook(({ val, cmp }) => usePreviousDistinct<T>(val as T, cmp), {\n      initialProps: {\n        val: initialValue || 0,\n        cmp: predicate,\n      } as { val?: T; cmp?: Predicate<T> },\n    });\n  }\n\n  it('should return undefined on init', () => {\n    expect(getHook().result.current).toBeUndefined();\n  });\n\n  it('should not invoke predicate on first render', () => {\n    const spy = jest.fn();\n    getHook(0, spy);\n\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('should update previous value only after render with different value', () => {\n    const hook = getHook();\n\n    expect(hook.result.current).toBeUndefined();\n\n    hook.rerender({ val: 0 });\n    expect(hook.result.current).toBeUndefined();\n\n    hook.rerender({ val: 1 });\n    expect(hook.result.current).toBe(0);\n\n    hook.rerender({ val: 2 });\n    expect(hook.result.current).toBe(1);\n\n    hook.rerender({ val: 2 });\n    expect(hook.result.current).toBe(1);\n\n    hook.rerender({ val: 3 });\n    expect(hook.result.current).toBe(2);\n  });\n\n  it('should work fine with `undefined` values', () => {\n    const hook = renderHook(({ value }) => usePreviousDistinct(value), {\n      initialProps: { value: undefined as undefined | number },\n    });\n\n    expect(hook.result.current).toBeUndefined();\n\n    hook.rerender({ value: 1 });\n    expect(hook.result.current).toBeUndefined();\n\n    hook.rerender({ value: undefined });\n    expect(hook.result.current).toBe(1);\n\n    hook.rerender({ value: 2 });\n    expect(hook.result.current).toBeUndefined();\n  });\n\n  it('should receive a predicate as a second parameter that will compare prev and current', () => {\n    const obj1 = { label: 'John', value: 'john' };\n    const obj2 = { label: 'Jonny', value: 'john' };\n    const obj3 = { label: 'Kate', value: 'kate' };\n    const predicate = (a, b) => !!a && a.value === b.value;\n\n    const hook = getHook(obj1 as { label: string; value: string }, predicate);\n\n    expect(hook.result.current).toBeUndefined();\n\n    hook.rerender({ val: obj2, cmp: predicate });\n\n    expect(hook.result.current).toBeUndefined();\n\n    hook.rerender({ val: obj3, cmp: predicate });\n\n    expect(hook.result.current).toBe(obj1);\n  });\n});\n"
  },
  {
    "path": "tests/useQueue.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useQueue from '../src/useQueue';\n\nconst setUp = (initialQueue?: any[]) => renderHook(() => useQueue(initialQueue));\n\nit('takes initial state', () => {\n  const { result } = setUp([1, 2, 3]);\n  const { first, last, size } = result.current;\n  expect(first).toEqual(1);\n  expect(last).toEqual(3);\n  expect(size).toEqual(3);\n});\n\nit('appends new member', () => {\n  const { result } = setUp([1, 2]);\n  act(() => {\n    result.current.add(3);\n  });\n  const { first, last, size } = result.current;\n  expect(first).toEqual(1);\n  expect(last).toEqual(3);\n  expect(size).toEqual(3);\n});\n\nit('pops oldest member', () => {\n  const { result } = setUp([1, 2]);\n  act(() => {\n    result.current.remove();\n  });\n  const { first, size } = result.current;\n  expect(first).toEqual(2);\n  expect(size).toEqual(1);\n});\n"
  },
  {
    "path": "tests/useRaf.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport { replaceRaf } from 'raf-stub';\nimport useRaf from '../src/useRaf';\n\n/**\n * New requestAnimationFrame after being replaced with raf-stub for testing purposes.\n */\ninterface RequestAnimationFrame {\n  reset(): void;\n\n  step(): void;\n}\n\ndeclare var requestAnimationFrame: RequestAnimationFrame;\n\nreplaceRaf();\nconst fixedStart = 1564949709496;\nconst spyDateNow = jest.spyOn(Date, 'now').mockImplementation(() => fixedStart);\n\nbeforeEach(() => {\n  jest.useFakeTimers();\n  requestAnimationFrame.reset();\n});\n\nafterEach(() => {\n  jest.clearAllTimers();\n  requestAnimationFrame.reset();\n});\n\nit('should init percentage of time elapsed', () => {\n  const { result } = renderHook(() => useRaf());\n  const timeElapsed = result.current;\n\n  expect(timeElapsed).toBe(0);\n});\n\nit('should return corresponding percentage of time elapsed for default ms', () => {\n  const { result } = renderHook(() => useRaf());\n  expect(result.current).toBe(0);\n\n  act(() => {\n    jest.runOnlyPendingTimers(); // start after delay\n    spyDateNow.mockImplementationOnce(() => fixedStart + 1e12 * 0.25); // 25%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(0.25);\n\n  act(() => {\n    spyDateNow.mockImplementationOnce(() => fixedStart + 1e12 * 0.5); // 50%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(0.5);\n\n  act(() => {\n    spyDateNow.mockImplementationOnce(() => fixedStart + 1e12 * 0.75); // 75%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(0.75);\n\n  act(() => {\n    spyDateNow.mockImplementationOnce(() => fixedStart + 1e12); // 100%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(1);\n});\n\nit('should return corresponding percentage of time elapsed for custom ms', () => {\n  const customMs = 2000;\n\n  const { result } = renderHook(() => useRaf(customMs));\n  expect(result.current).toBe(0);\n\n  act(() => {\n    jest.runOnlyPendingTimers(); // start after delay\n    spyDateNow.mockImplementationOnce(() => fixedStart + customMs * 0.25); // 25%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(0.25);\n\n  act(() => {\n    spyDateNow.mockImplementationOnce(() => fixedStart + customMs * 0.5); // 50%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(0.5);\n\n  act(() => {\n    spyDateNow.mockImplementationOnce(() => fixedStart + customMs * 0.75); // 75%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(0.75);\n\n  act(() => {\n    spyDateNow.mockImplementationOnce(() => fixedStart + customMs); // 100%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(1);\n});\n\nit('should return always 1 after corresponding ms reached', () => {\n  const { result } = renderHook(() => useRaf());\n  expect(result.current).toBe(0);\n\n  act(() => {\n    jest.runOnlyPendingTimers(); // start after delay\n    spyDateNow.mockImplementationOnce(() => fixedStart + 1e12); // 100%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(1);\n\n  act(() => {\n    spyDateNow.mockImplementationOnce(() => fixedStart + 1e12 * 1.1); // 110%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(1);\n\n  act(() => {\n    spyDateNow.mockImplementationOnce(() => fixedStart + 1e12 * 3); // 300%\n    requestAnimationFrame.step();\n  });\n  expect(result.current).toBe(1);\n});\n\nit('should wait until delay reached to start calculating elapsed percentage', () => {\n  const { result } = renderHook(() => useRaf(undefined, 500));\n\n  expect(result.current).toBe(0);\n\n  act(() => {\n    jest.advanceTimersByTime(250); // fast-forward only half of custom delay\n  });\n  expect(result.current).toBe(0);\n\n  act(() => {\n    jest.advanceTimersByTime(249); // fast-forward 1ms less than custom delay\n  });\n  expect(result.current).toBe(0);\n\n  act(() => {\n    jest.advanceTimersByTime(1); // fast-forward exactly to custom delay\n  });\n  expect(result.current).not.toBe(0);\n});\n\nit('should clear pending timers on unmount', () => {\n  const spyRafStop = jest.spyOn(global, 'cancelAnimationFrame' as any);\n  const { unmount } = renderHook(() => useRaf());\n\n  expect(clearTimeout).not.toHaveBeenCalled();\n  expect(spyRafStop).not.toHaveBeenCalled();\n\n  unmount();\n\n  expect(clearTimeout).toHaveBeenCalledTimes(2);\n  expect(spyRafStop).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "tests/useRafLoop.test.tsx",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { replaceRaf } from 'raf-stub';\nimport useRafLoop from '../src/useRafLoop';\n\ndeclare var requestAnimationFrame: {\n  add: (cb: Function) => number;\n  remove: (id: number) => void;\n  flush: (duration?: number) => void;\n  reset: () => void;\n  step: (steps?: number, duration?: number) => void;\n};\n\ndescribe('useRafLoop', () => {\n  beforeAll(() => {\n    replaceRaf();\n  });\n\n  afterEach(() => {\n    requestAnimationFrame.reset();\n  });\n\n  it('should be defined', () => {\n    expect(useRafLoop).toBeDefined();\n  });\n\n  it('should return object with start, stop and isActive functions', () => {\n    const hook = renderHook(() => useRafLoop(() => false), { initialProps: false });\n\n    expect(hook.result.current).toStrictEqual([\n      expect.any(Function),\n      expect.any(Function),\n      expect.any(Function),\n    ]);\n  });\n\n  it('should constantly call callback inside the raf loop', () => {\n    const spy = jest.fn();\n    renderHook(() => useRafLoop(spy), { initialProps: false });\n\n    expect(spy).not.toBeCalled();\n    requestAnimationFrame.step(2);\n    expect(spy).toBeCalledTimes(2);\n    requestAnimationFrame.step(2);\n    expect(spy).toBeCalledTimes(4);\n  });\n\n  it('should not start the loop if 2nd hook parameter is falsy', () => {\n    const spy = jest.fn();\n    renderHook(() => useRafLoop(spy, false), { initialProps: false });\n\n    expect(spy).not.toBeCalled();\n    requestAnimationFrame.step(2);\n    expect(spy).not.toBeCalled();\n  });\n\n  it('should pass the time argument to given callback', () => {\n    const spy = jest.fn();\n    renderHook(() => useRafLoop(spy), { initialProps: false });\n\n    expect(spy).not.toBeCalled();\n    requestAnimationFrame.step();\n    expect(typeof spy.mock.calls[0][0]).toBe('number');\n  });\n\n  it('should stop the loop on component unmount', () => {\n    const spy = jest.fn();\n    const hook = renderHook(() => useRafLoop(spy), { initialProps: false });\n\n    expect(spy).not.toBeCalled();\n    requestAnimationFrame.step(2);\n    expect(spy).toBeCalledTimes(2);\n\n    hook.unmount();\n\n    requestAnimationFrame.step(2);\n    expect(spy).toBeCalledTimes(2);\n  });\n\n  it('should call the actual callback when it changed', () => {\n    const spy1 = jest.fn();\n    const spy2 = jest.fn();\n    const hook = renderHook(({ cb }) => useRafLoop(cb), { initialProps: { cb: spy1 } });\n\n    expect(spy1).not.toBeCalled();\n    requestAnimationFrame.step(2);\n    expect(spy1).toBeCalledTimes(2);\n\n    hook.rerender({ cb: spy2 });\n\n    requestAnimationFrame.step(2);\n    expect(spy1).toBeCalledTimes(2);\n    expect(spy2).toBeCalledTimes(2);\n  });\n\n  describe('returned methods', () => {\n    it('stop method should stop the loop', () => {\n      const spy = jest.fn();\n      const hook = renderHook(() => useRafLoop(spy), { initialProps: false });\n\n      const [stop] = hook.result.current;\n\n      expect(spy).not.toBeCalled();\n      requestAnimationFrame.step(2);\n      expect(spy).toBeCalledTimes(2);\n\n      stop();\n\n      requestAnimationFrame.step(2);\n      expect(spy).toBeCalledTimes(2);\n    });\n\n    it('start method should start stopped loop', () => {\n      const spy = jest.fn();\n      const hook = renderHook(() => useRafLoop(spy, false), { initialProps: false });\n\n      const [stop, start] = hook.result.current;\n\n      expect(spy).not.toBeCalled();\n      requestAnimationFrame.step(2);\n      expect(spy).not.toBeCalled();\n\n      start();\n\n      requestAnimationFrame.step(2);\n      expect(spy).toBeCalledTimes(2);\n\n      stop();\n\n      requestAnimationFrame.step(2);\n      expect(spy).toBeCalledTimes(2);\n\n      start();\n\n      requestAnimationFrame.step(2);\n      expect(spy).toBeCalledTimes(4);\n    });\n\n    it('isActive method should return current loop state', () => {\n      const spy = jest.fn();\n      const hook = renderHook(() => useRafLoop(spy, false), { initialProps: false });\n\n      const [stop, start, isActive] = hook.result.current;\n\n      expect(isActive()).toBe(false);\n      start();\n      expect(isActive()).toBe(true);\n      stop();\n      expect(isActive()).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/useRafState.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport { replaceRaf } from 'raf-stub';\nimport useRafState from '../src/useRafState';\n\ninterface RequestAnimationFrame {\n  reset(): void;\n  step(): void;\n}\n\ndeclare var requestAnimationFrame: RequestAnimationFrame;\n\nreplaceRaf();\n\nbeforeEach(() => {\n  requestAnimationFrame.reset();\n});\n\nafterEach(() => {\n  requestAnimationFrame.reset();\n});\n\ndescribe('useRafState', () => {\n  it('should be defined', () => {\n    expect(useRafState).toBeDefined();\n  });\n\n  it('should only update state after requestAnimationFrame when providing an object', () => {\n    const { result } = renderHook(() => useRafState(0));\n\n    act(() => {\n      result.current[1](1);\n    });\n    expect(result.current[0]).toBe(0);\n\n    act(() => {\n      requestAnimationFrame.step();\n    });\n    expect(result.current[0]).toBe(1);\n\n    act(() => {\n      result.current[1](2);\n      requestAnimationFrame.step();\n    });\n    expect(result.current[0]).toBe(2);\n\n    act(() => {\n      result.current[1]((prevState) => prevState * 2);\n      requestAnimationFrame.step();\n    });\n    expect(result.current[0]).toBe(4);\n  });\n\n  it('should only update state after requestAnimationFrame when providing a function', () => {\n    const { result } = renderHook(() => useRafState(0));\n\n    act(() => {\n      result.current[1]((prevState) => prevState + 1);\n    });\n    expect(result.current[0]).toBe(0);\n\n    act(() => {\n      requestAnimationFrame.step();\n    });\n    expect(result.current[0]).toBe(1);\n\n    act(() => {\n      result.current[1]((prevState) => prevState * 3);\n      requestAnimationFrame.step();\n    });\n    expect(result.current[0]).toBe(3);\n  });\n\n  it('should cancel update state on unmount', () => {\n    const { unmount } = renderHook(() => useRafState(0));\n    const spyRafCancel = jest.spyOn(global, 'cancelAnimationFrame' as any);\n\n    expect(spyRafCancel).not.toHaveBeenCalled();\n\n    unmount();\n\n    expect(spyRafCancel).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "tests/useRendersCount.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useRendersCount } from '../src';\n\ndescribe('useRendersCount', () => {\n  it('should be defined', () => {\n    expect(useRendersCount).toBeDefined();\n  });\n\n  it('should return number', () => {\n    expect(renderHook(() => useRendersCount()).result.current).toEqual(expect.any(Number));\n  });\n\n  it('should return actual number of renders', () => {\n    const hook = renderHook(() => useRendersCount());\n\n    expect(hook.result.current).toBe(1);\n    hook.rerender();\n    expect(hook.result.current).toBe(2);\n    hook.rerender();\n    expect(hook.result.current).toBe(3);\n  });\n});\n"
  },
  {
    "path": "tests/useScrollbarWidth.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport { scrollbarWidth } from '@xobotyi/scrollbar-width';\nimport { useScrollbarWidth } from '../src';\nimport { replaceRaf } from 'raf-stub';\n\ndeclare var requestAnimationFrame: {\n  add: (cb: Function) => number;\n  remove: (id: number) => void;\n  flush: (duration?: number) => void;\n  reset: () => void;\n  step: (steps?: number, duration?: number) => void;\n};\n\ndescribe('useScrollbarWidth', () => {\n  beforeAll(() => {\n    replaceRaf();\n  });\n\n  afterEach(() => {\n    requestAnimationFrame.reset();\n  });\n\n  it('should be defined', () => {\n    expect(useScrollbarWidth).toBeDefined();\n  });\n\n  it('should return value of scrollbarWidth result', () => {\n    scrollbarWidth.__cache = 21;\n    const { result } = renderHook(() => useScrollbarWidth());\n\n    expect(result.current).toBe(21);\n  });\n\n  it('should re-call scrollbar width in RAF in case `scrollbarWidth()` returned undefined', () => {\n    scrollbarWidth.__cache = undefined;\n    const { result } = renderHook(() => useScrollbarWidth());\n    expect(result.current).toBe(undefined);\n    scrollbarWidth.__cache = 34;\n    act(() => {\n      requestAnimationFrame.step();\n    });\n\n    expect(result.current).toBe(34);\n  });\n});\n"
  },
  {
    "path": "tests/useSearchParam.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useSearchParam from '../src/useSearchParam';\n\nconst { location } = window;\n\nlet mockSearch: string;\n\nbeforeEach(() => {\n  delete (window as any).location;\n  const { search, ...restLocation } = location;\n\n  // @ts-ignore\n  window.location = { ...restLocation };\n\n  Object.defineProperty(window.location, 'search', {\n    get: function () {\n      return mockSearch;\n    },\n  });\n});\n\nit('returns current location.search value', () => {\n  mockSearch = 'foo=bar&baz=quux';\n\n  const { result } = renderHook(() => useSearchParam('foo'));\n\n  expect(result.current).toBe('bar');\n});\n\nit('returns null if search param not found', () => {\n  mockSearch = 'foo=bar&baz=quux';\n\n  const { result } = renderHook(() => useSearchParam('foo2'));\n\n  expect(result.current).toBe(null);\n});\n\nit('tracks the latest search param value', () => {\n  mockSearch = 'foo=bar&baz=quux';\n\n  let callback;\n  const window$addEventListener = window.addEventListener;\n  window.addEventListener = (event, cb) => {\n    if (event === 'pushstate') {\n      callback = cb;\n    }\n  };\n\n  const { result } = renderHook(() => useSearchParam('baz'));\n\n  expect(result.current).toBe('quux');\n\n  act(() => {\n    mockSearch = 'foo=1&baz=2';\n    callback();\n  });\n\n  expect(result.current).toBe('2');\n\n  window.addEventListener = window$addEventListener;\n});\n"
  },
  {
    "path": "tests/useSet.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useSet from '../src/useSet';\n\nconst setUp = <K>(initialSet?: Set<K>) => renderHook(() => useSet(initialSet));\n\nit('should init set and utils', () => {\n  const { result } = setUp(new Set([1, 2]));\n  const [set, utils] = result.current;\n\n  expect(set).toEqual(new Set([1, 2]));\n  expect(utils).toStrictEqual({\n    has: expect.any(Function),\n    add: expect.any(Function),\n    remove: expect.any(Function),\n    toggle: expect.any(Function),\n    reset: expect.any(Function),\n    clear: expect.any(Function),\n  });\n});\n\nit('should init empty set if no initial set provided', () => {\n  const { result } = setUp();\n\n  expect(result.current[0]).toEqual(new Set());\n});\n\nit('should have an initially provided key', () => {\n  const { result } = setUp(new Set(['a']));\n  const [, utils] = result.current;\n\n  let value;\n  act(() => {\n    value = utils.has('a');\n  });\n\n  expect(value).toBe(true);\n});\n\nit('should have an added key', () => {\n  const { result } = setUp(new Set());\n\n  act(() => {\n    result.current[1].add('newKey');\n  });\n\n  let value;\n  act(() => {\n    value = result.current[1].has('newKey');\n  });\n\n  expect(value).toBe(true);\n});\n\nit('should get false for non-existing key', () => {\n  const { result } = setUp(new Set(['a']));\n  const [, utils] = result.current;\n\n  let value;\n  act(() => {\n    value = utils.has('nonExisting');\n  });\n\n  expect(value).toBe(false);\n});\n\nit('should add a new key', () => {\n  const { result } = setUp(new Set(['oldKey']));\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.add('newKey');\n  });\n\n  expect(result.current[0]).toEqual(new Set(['oldKey', 'newKey']));\n});\n\nit('should work if setting existing key', () => {\n  const { result } = setUp(new Set(['oldKey']));\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.add('oldKey');\n  });\n\n  expect(result.current[0]).toEqual(new Set(['oldKey']));\n});\n\nit('should remove existing key', () => {\n  const { result } = setUp(new Set([1, 2]));\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.remove(2);\n  });\n\n  expect(result.current[0]).toEqual(new Set([1]));\n});\n\nit('should remove an existing key on toggle', () => {\n  const { result } = setUp(new Set([1, 2]));\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.toggle(2);\n  });\n\n  expect(result.current[0]).toEqual(new Set([1]));\n});\n\nit('should add a new key on toggle', () => {\n  const { result } = setUp(new Set([1]));\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.toggle(2);\n  });\n\n  expect(result.current[0]).toEqual(new Set([1, 2]));\n});\n\nit('should do nothing if removing non-existing key', () => {\n  const { result } = setUp(new Set(['a', 'b']));\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.remove('nonExisting');\n  });\n\n  expect(result.current[0]).toEqual(new Set(['a', 'b']));\n});\n\nit('should reset to initial set provided', () => {\n  const { result } = setUp(new Set([1]));\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.add(2);\n  });\n\n  expect(result.current[0]).toEqual(new Set([1, 2]));\n\n  act(() => {\n    utils.reset();\n  });\n\n  expect(result.current[0]).toEqual(new Set([1]));\n});\n\nit('should be empty', () => {\n  const { result } = setUp(new Set([1]));\n  const [, utils] = result.current;\n\n  act(() => {\n    utils.clear();\n  });\n\n  expect(result.current[0]).toEqual(new Set([]));\n});\n\nit('should memoized its utils methods', () => {\n  const { result } = setUp(new Set(['a', 'b']));\n  const [, utils] = result.current;\n  const { add, remove, reset, clear, toggle } = utils;\n\n  act(() => {\n    add('foo');\n  });\n\n  expect(result.current[1].add).toBe(add);\n  expect(result.current[1].remove).toBe(remove);\n  expect(result.current[1].toggle).toBe(toggle);\n  expect(result.current[1].reset).toBe(reset);\n  expect(result.current[1].clear).toBe(clear);\n});\n"
  },
  {
    "path": "tests/useSetState.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useSetState from '../src/useSetState';\n\nconst setUp = (initialState?: object) => renderHook(() => useSetState(initialState));\n\nit('should init state and setter', () => {\n  const { result } = setUp({ foo: 'bar' });\n  const [state, setState] = result.current;\n\n  expect(state).toEqual({ foo: 'bar' });\n  expect(setState).toBeInstanceOf(Function);\n});\n\nit('should init empty state if not initial state provided', () => {\n  const { result } = setUp();\n\n  expect(result.current[0]).toEqual({});\n});\n\nit('should merge changes into current state when providing object', () => {\n  const { result } = setUp({ foo: 'bar', count: 1 });\n  const [state, setState] = result.current;\n\n  act(() => {\n    // @ts-ignore\n    setState({ count: state.count + 1, someBool: true });\n  });\n\n  expect(result.current[0]).toEqual({ foo: 'bar', count: 2, someBool: true });\n});\n\nit('should merge changes into current state when providing function', () => {\n  const { result } = setUp({ foo: 'bar', count: 1 });\n  const [, setState] = result.current;\n\n  act(() => {\n    // @ts-ignore\n    setState((prevState) => ({ count: prevState.count + 1, someBool: true }));\n  });\n\n  expect(result.current[0]).toEqual({ foo: 'bar', count: 2, someBool: true });\n});\n\n/**\n * Enforces cases where a hook can safely depend on the callback without\n * causing an endless rerender cycle: useEffect(() => setState({ data }), [setState]);\n */\nit('should return a memoized setState callback', () => {\n  const { result, rerender } = setUp({ ok: false });\n  const [, setState1] = result.current;\n\n  act(() => {\n    setState1({ ok: true });\n  });\n  rerender();\n\n  const [, setState2] = result.current;\n\n  expect(setState1).toBe(setState2);\n});\n"
  },
  {
    "path": "tests/useShallowCompareEffect.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useShallowCompareEffect } from '../src';\nimport { useEffect } from 'react';\n\nlet options1 = { max: 10, range: { from: 0, to: 10 } };\nconst options2 = { max: 10, range: { from: 0, to: 10 } };\nconst mockEffectNormal = jest.fn();\nconst mockEffectShallow = jest.fn();\nconst mockEffectCleanup = jest.fn();\nconst mockEffectCallback = jest.fn().mockReturnValue(mockEffectCleanup);\n\nit('should shallow compare dependencies', () => {\n  const { rerender: rerenderNormal } = renderHook(() =>\n    useEffect(mockEffectNormal, [options1, options2])\n  );\n  const { rerender: rerenderShallow } = renderHook(() =>\n    useShallowCompareEffect(mockEffectShallow, [options1, options2])\n  );\n\n  expect(mockEffectNormal).toHaveBeenCalledTimes(1);\n  expect(mockEffectShallow).toHaveBeenCalledTimes(1);\n\n  options1 = { max: 10, range: options1.range };\n  rerenderShallow();\n  rerenderNormal();\n\n  expect(mockEffectNormal).toHaveBeenCalledTimes(2);\n  expect(mockEffectShallow).toHaveBeenCalledTimes(1);\n\n  options1 = { max: 10, range: { from: 0, to: 10 } };\n  rerenderNormal();\n  rerenderShallow();\n\n  expect(mockEffectNormal).toHaveBeenCalledTimes(3);\n  expect(mockEffectShallow).toHaveBeenCalledTimes(2);\n});\n\nit('should run clean-up provided on unmount', () => {\n  const { unmount } = renderHook(() =>\n    useShallowCompareEffect(mockEffectCallback, [options1, options2])\n  );\n  expect(mockEffectCleanup).not.toHaveBeenCalled();\n\n  unmount();\n  expect(mockEffectCleanup).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "tests/useSpring.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport { Spring } from 'rebound';\nimport useSpring from '../src/useSpring';\n\n// simulate Spring for testing\nconst mockSetCurrentValue = jest.fn();\nconst mockAddListener = jest.fn();\nconst mockSetEndValue = jest.fn();\nconst mockRemoveListener = jest.fn();\nlet triggerSpringUpdate = () => {};\nlet springListener: Listener = { onSpringUpdate: () => {} };\n\ninterface Listener {\n  onSpringUpdate: (currentSpring: Spring) => void;\n}\n\nconst mockCreateSpring: Spring = jest.fn().mockImplementation(() => {\n  let currentValue = 0;\n  let endValue = 0;\n\n  const getCloserValue = (a, b) => Math.round((a + b) / 2);\n\n  const getCurrentValue = () => {\n    currentValue = getCloserValue(currentValue, endValue);\n    return currentValue;\n  };\n\n  triggerSpringUpdate = () => {\n    if (currentValue !== endValue) {\n      springListener.onSpringUpdate({ getCurrentValue } as any);\n    }\n  };\n\n  return {\n    setCurrentValue: (val) => {\n      currentValue = val;\n      mockSetCurrentValue(val);\n    },\n    addListener: (newListener) => {\n      springListener = newListener;\n      mockAddListener(newListener);\n    },\n    setEndValue: (val) => {\n      endValue = val;\n      mockSetEndValue(val);\n    },\n    removeListener: mockRemoveListener,\n  };\n}) as any;\n\njest.mock('rebound', () => {\n  return {\n    Sprint: {},\n    SpringSystem: jest.fn().mockImplementation(() => {\n      return { createSpring: mockCreateSpring };\n    }),\n  };\n});\n\nit('should init value to provided target', () => {\n  const { result } = renderHook(() => useSpring(70));\n\n  expect(result.current).toBe(70);\n  expect(mockSetCurrentValue).toHaveBeenCalledTimes(1);\n  expect(mockSetCurrentValue).toHaveBeenCalledWith(70);\n  expect(mockCreateSpring).toHaveBeenCalledTimes(1);\n  expect(mockCreateSpring).toHaveBeenCalledWith(50, 3);\n});\n\nit('should create spring with custom tension and friction args provided', () => {\n  renderHook(() => useSpring(500, 20, 7));\n\n  expect(mockCreateSpring).toHaveBeenCalledTimes(1);\n  expect(mockCreateSpring).toHaveBeenCalledWith(20, 7);\n});\n\nit('should subscribe only once', () => {\n  const { rerender } = renderHook(() => useSpring());\n\n  expect(mockAddListener).toHaveBeenCalledTimes(1);\n  expect(mockAddListener).toHaveBeenCalledWith(springListener);\n\n  rerender();\n\n  expect(mockAddListener).toHaveBeenCalledTimes(1);\n});\n\nit('should handle spring update', () => {\n  let targetValue = 70;\n  let lastSpringValue = targetValue;\n  const { result, rerender } = renderHook(() => useSpring(targetValue));\n\n  targetValue = 100;\n  rerender();\n  expect(result.current).toBe(lastSpringValue);\n\n  act(() => {\n    triggerSpringUpdate(); // simulate new spring value\n  });\n  expect(result.current).toBeGreaterThan(lastSpringValue);\n  expect(result.current).toBeLessThanOrEqual(targetValue);\n\n  lastSpringValue = result.current;\n  act(() => {\n    triggerSpringUpdate(); // simulate another new spring value\n  });\n  expect(result.current).toBeGreaterThan(lastSpringValue);\n  expect(result.current).toBeLessThanOrEqual(targetValue);\n});\n\nit('should remove listener on unmount', () => {\n  const { unmount } = renderHook(() => useSpring());\n  expect(mockRemoveListener).not.toHaveBeenCalled();\n\n  unmount();\n\n  expect(mockRemoveListener).toHaveBeenCalledTimes(1);\n  expect(mockRemoveListener).toHaveBeenCalledWith(springListener);\n});\n"
  },
  {
    "path": "tests/useStateList.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useStateList from '../src/useStateList';\n\ndescribe('useStateList', () => {\n  it('should be defined', () => {\n    expect(useStateList).toBeDefined();\n  });\n\n  function getHook(list: any[] = ['a', 'b', 'c']) {\n    return renderHook(({ states }) => useStateList(states), { initialProps: { states: list } });\n  }\n\n  it('should return an object containing `state`, `next` and `prev`', () => {\n    const res = getHook().result.current;\n\n    expect(res).toStrictEqual({\n      state: expect.any(String),\n      currentIndex: expect.any(Number),\n      prev: expect.any(Function),\n      next: expect.any(Function),\n      setStateAt: expect.any(Function),\n      setState: expect.any(Function),\n      isFirst: expect.any(Boolean),\n      isLast: expect.any(Boolean),\n    });\n  });\n\n  it('should return the first state on init', () => {\n    expect(getHook().result.current.state).toBe('a');\n  });\n\n  it('should return isFirst on init', () => {\n    expect(getHook().result.current.isFirst).toBe(true);\n  });\n\n  it('should return isLast when on last state', () => {\n    const hook = getHook();\n    act(() => hook.result.current.setStateAt(2));\n\n    expect(hook.result.current.isLast).toBe(true);\n  });\n\n  describe('setState()', () => {\n    it('should set state value if it exists in states list', () => {\n      const hook = getHook();\n\n      expect(hook.result.current.state).toBe('a');\n\n      act(() => hook.result.current.setState('c'));\n\n      expect(hook.result.current.state).toBe('c');\n    });\n\n    it('should throw if required state not exists', () => {\n      const hook = getHook();\n\n      expect(hook.result.current.state).toBe('a');\n\n      expect(() => hook.result.current.setState('d')).toThrow(\n        `State 'd' is not a valid state (does not exist in state list)`\n      );\n    });\n\n    it('should do nothing on unmounted component', () => {\n      const hook = getHook();\n\n      expect(hook.result.current.state).toBe('a');\n      hook.unmount();\n\n      expect(() => hook.result.current.setState('c')).not.toThrow(Error);\n      expect(hook.result.current.state).toBe('a');\n    });\n  });\n\n  describe('setStateAt()', () => {\n    it('should set state by it`s index in states list', () => {\n      const hook = getHook();\n\n      expect(hook.result.current.state).toBe('a');\n\n      act(() => hook.result.current.setStateAt(2));\n      expect(hook.result.current.state).toBe('c');\n      act(() => hook.result.current.setStateAt(1));\n      expect(hook.result.current.state).toBe('b');\n    });\n\n    it('should cyclically travel through the right border', () => {\n      const hook = getHook();\n\n      expect(hook.result.current.state).toBe('a');\n\n      act(() => hook.result.current.setStateAt(5));\n      expect(hook.result.current.state).toBe('c');\n      act(() => hook.result.current.setStateAt(9));\n      expect(hook.result.current.state).toBe('a');\n      act(() => hook.result.current.setStateAt(10));\n      expect(hook.result.current.state).toBe('b');\n    });\n\n    it('should cyclically travel through the left border', () => {\n      const hook = getHook();\n\n      expect(hook.result.current.state).toBe('a');\n\n      act(() => hook.result.current.setStateAt(-1));\n      expect(hook.result.current.state).toBe('c');\n      act(() => hook.result.current.setStateAt(-2));\n      expect(hook.result.current.state).toBe('b');\n      act(() => hook.result.current.setStateAt(-17));\n      expect(hook.result.current.state).toBe('b');\n    });\n  });\n\n  describe('next()', () => {\n    it('should switch states forward and cause re-render', () => {\n      const hook = getHook();\n\n      expect(hook.result.current.state).toBe('a');\n\n      act(() => {\n        hook.result.current.next();\n      });\n      expect(hook.result.current.state).toBe('b');\n\n      act(() => {\n        hook.result.current.next();\n      });\n      expect(hook.result.current.state).toBe('c');\n    });\n\n    it('on overflow should switch to first element (should be cycled)', () => {\n      const hook = getHook();\n\n      expect(hook.result.current.state).toBe('a');\n\n      act(() => {\n        hook.result.current.next();\n        hook.result.current.next();\n        hook.result.current.next();\n      });\n      expect(hook.result.current.state).toBe('a');\n    });\n  });\n\n  describe('prev()', () => {\n    it('on overflow should switch to last element (should be cycled)', () => {\n      const hook = getHook();\n\n      expect(hook.result.current.state).toBe('a');\n\n      act(() => {\n        hook.result.current.prev();\n      });\n      expect(hook.result.current.state).toBe('c');\n    });\n\n    it('should switch states backward and cause re-render', () => {\n      const hook = getHook();\n\n      expect(hook.result.current.state).toBe('a');\n\n      act(() => {\n        hook.result.current.prev();\n      });\n      expect(hook.result.current.state).toBe('c');\n\n      act(() => {\n        hook.result.current.prev();\n      });\n      expect(hook.result.current.state).toBe('b');\n\n      act(() => {\n        hook.result.current.prev();\n      });\n      expect(hook.result.current.state).toBe('a');\n    });\n  });\n\n  describe('with empty states list', () => {\n    it('should have `undefined` state', () => {\n      expect(getHook([]).result.current.state).toBe(undefined);\n    });\n\n    it('should do nothing on next() call', () => {\n      const hook = getHook([]);\n      act(() => {\n        hook.result.current.next();\n      });\n\n      expect(hook.result.current.state).toBe(undefined);\n    });\n\n    it('should do nothing on prev() call', () => {\n      const hook = getHook([]);\n      act(() => {\n        hook.result.current.prev();\n      });\n\n      expect(hook.result.current.state).toBe(undefined);\n    });\n  });\n\n  describe('on state list shrink', () => {\n    it('should set last element as state if index was beyond new last element', () => {\n      const hook = getHook();\n      act(() => {\n        hook.result.current.prev();\n      });\n      expect(hook.result.current.state).toBe('c');\n\n      hook.rerender({ states: ['a', 'b'] });\n\n      expect(hook.result.current.state).toBe('b');\n    });\n\n    it('should so nothing if current index within new range', () => {\n      const hook = getHook();\n      act(() => {\n        hook.result.current.prev();\n      });\n      expect(hook.result.current.state).toBe('c');\n\n      hook.rerender({ states: ['a', 'b', 'c', 'd'] });\n\n      expect(hook.result.current.state).toBe('c');\n    });\n  });\n\n  describe('ou unmounted component', () => {\n    it('next() should not do anything', () => {\n      const hook = getHook();\n      const { next } = hook.result.current;\n\n      hook.unmount();\n      act(() => next());\n\n      expect(hook.result.current.state).toBe('a');\n    });\n\n    it('prev() should not do anything', () => {\n      const hook = getHook();\n      const { prev } = hook.result.current;\n\n      hook.unmount();\n      act(() => prev());\n\n      expect(hook.result.current.state).toBe('a');\n    });\n  });\n});\n"
  },
  {
    "path": "tests/useStateValidator.test.ts",
    "content": "import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks';\nimport { useState } from 'react';\nimport useStateValidator, {\n  StateValidator,\n  UseStateValidatorReturn,\n} from '../src/useStateValidator';\n\ninterface Mock extends jest.Mock {}\n\ndescribe('useStateValidator', () => {\n  it('should be defined', () => {\n    expect(useStateValidator).toBeDefined();\n  });\n\n  function getHook(\n    fn: StateValidator<[boolean], number> = jest.fn((state): [boolean] => [!!(state % 2)])\n  ): [jest.Mock | Function, RenderHookResult<any, [Function, UseStateValidatorReturn<any>]>] {\n    return [\n      fn,\n      renderHook(() => {\n        const [state, setState] = useState(1);\n\n        return [setState, useStateValidator(state, fn)];\n      }),\n    ];\n  }\n\n  it('should return an array of two elements', () => {\n    const [, hook] = getHook();\n    const res = hook.result.current[1];\n\n    expect(Array.isArray(res)).toBe(true);\n    expect(res[0]).toEqual([true]);\n    expect(typeof res[1]).toBe('function');\n  });\n\n  it('first element should represent current validity state', () => {\n    const [, hook] = getHook();\n    let [setState, [validity]] = hook.result.current;\n    expect(validity).toEqual([true]);\n\n    act(() => setState(3));\n    [setState, [validity]] = hook.result.current;\n    expect(validity).toEqual([true]);\n\n    act(() => setState(4));\n    [setState, [validity]] = hook.result.current;\n    expect(validity).toEqual([false]);\n  });\n\n  it('second element should re-call validation', () => {\n    const [spy, hook] = getHook();\n    const [, [, revalidate]] = hook.result.current;\n\n    expect(spy).toHaveBeenCalledTimes(1);\n    act(() => revalidate());\n    expect(spy).toHaveBeenCalledTimes(2);\n  });\n\n  it('validator have to be called on init plus on each state update', () => {\n    const [spy, hook] = getHook(jest.fn());\n    const [setState] = hook.result.current;\n\n    expect(spy).toHaveBeenCalledTimes(1);\n    act(() => setState(4));\n    expect(spy).toHaveBeenCalledTimes(2);\n    act(() => setState((prevState) => prevState + 1));\n    expect(spy).toHaveBeenCalledTimes(3);\n  });\n\n  it('should pass to validator one parameter - current state', () => {\n    const [spy, hook] = getHook(jest.fn());\n    const [setState] = hook.result.current;\n\n    act(() => setState(4));\n    act(() => setState(5));\n    expect((spy as Mock).mock.calls[0].length).toBe(1);\n    expect((spy as Mock).mock.calls[0].length).toBe(1);\n    expect((spy as Mock).mock.calls[0][0]).toBe(1);\n    expect((spy as Mock).mock.calls[1].length).toBe(1);\n    expect((spy as Mock).mock.calls[1][0]).toBe(4);\n    expect((spy as Mock).mock.calls[2].length).toBe(1);\n    expect((spy as Mock).mock.calls[2][0]).toBe(5);\n  });\n\n  it('if validator expects 2nd parameter it should pass a validity setter there', () => {\n    const [spy, hook] = getHook(\n      jest.fn((state, setValidity): void => {\n        setValidity([state % 2 === 0]);\n      }) as unknown as StateValidator<[boolean], number>\n    );\n    let [setState, [[isValid]]] = hook.result.current;\n\n    expect((spy as Mock).mock.calls[0].length).toBe(2);\n    expect(typeof (spy as Mock).mock.calls[0][1]).toBe('function');\n\n    expect(isValid).toBe(false);\n    act(() => setState((prevState) => prevState + 1));\n\n    [setState, [[isValid]]] = hook.result.current;\n    expect(isValid).toBe(true);\n    act(() => setState(5));\n\n    [setState, [[isValid]]] = hook.result.current;\n    expect(isValid).toBe(false);\n  });\n});\n"
  },
  {
    "path": "tests/useStateWithHistory.test.ts",
    "content": "import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks';\nimport { useRef } from 'react';\nimport { UseStateHistoryReturn, useStateWithHistory } from '../src/useStateWithHistory';\nimport { IHookStateSetAction } from '../src/misc/hookState';\n\ndescribe('useStateWithHistory', () => {\n  it('should be defined', () => {\n    expect(useStateWithHistory).toBeDefined();\n  });\n\n  function getHook<S, I extends S>(\n    initialState?: IHookStateSetAction<S>,\n    initialCapacity?: number,\n    initialHistory?: I[]\n  ): RenderHookResult<\n    { state?: S; history?: I[]; capacity?: number },\n    [UseStateHistoryReturn<S | undefined>, number]\n  > {\n    return renderHook(\n      ({ state, history, capacity }) => {\n        const renders = useRef(0);\n        renders.current++;\n        return [useStateWithHistory(state, capacity, history), renders.current];\n      },\n      {\n        initialProps: {\n          state: initialState,\n          history: initialHistory,\n          capacity: initialCapacity,\n        } as { state?: S; history?: I[]; capacity?: number },\n      }\n    );\n  }\n\n  it('should return state, state setter and history structure', () => {\n    const res = getHook(0).result.current[0];\n\n    expect(res).toStrictEqual([expect.any(Number), expect.any(Function), expect.any(Object)]);\n    expect(res[2]).toStrictEqual({\n      history: expect.any(Array),\n      position: expect.any(Number),\n      capacity: expect.any(Number),\n      back: expect.any(Function),\n      forward: expect.any(Function),\n      go: expect.any(Function),\n    });\n  });\n\n  it('should act like regular setState', () => {\n    const hook = getHook(() => 1);\n\n    expect(hook.result.current[0][0]).toBe(1);\n    act(() => {\n      hook.result.current[0][1](321);\n    });\n    expect(hook.result.current[0][0]).toBe(321);\n    act(() => {\n      hook.result.current[0][1]((current) => (current ?? 0) + 111);\n    });\n    expect(hook.result.current[0][0]).toBe(432);\n  });\n\n  it('should receive initial history', () => {\n    const hook = getHook(3, undefined, [1, 2, 3]);\n    expect(hook.result.current[0][2].history).toEqual([1, 2, 3]);\n  });\n\n  it('should push initial state to initial history if last element not equals it', () => {\n    const hook = getHook(1, undefined, [1, 2, 3]);\n    expect(hook.result.current[0][2].history).toEqual([1, 2, 3, 1]);\n  });\n\n  it('should crop initial history in case it exceeds capacity', () => {\n    const hook = getHook(10, 5, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);\n    expect(hook.result.current[0][2].history).toEqual([6, 7, 8, 9, 10]);\n  });\n\n  it('should apply capacity change only with next state set', () => {\n    const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n    expect(hook.result.current[0][2].capacity).toBe(5);\n    expect(hook.result.current[0][2].history).toEqual([1, 2, 3, 4, 5]);\n\n    hook.rerender({ state: 5, capacity: 4, history: [1, 2, 3, 4, 5] });\n\n    expect(hook.result.current[0][2].capacity).toBe(5);\n    expect(hook.result.current[0][2].history).toEqual([1, 2, 3, 4, 5]);\n\n    act(() => {\n      hook.result.current[0][1](() => 111);\n    });\n\n    expect(hook.result.current[0][0]).toBe(111);\n    expect(hook.result.current[0][2].capacity).toBe(4);\n    expect(hook.result.current[0][2].history).toEqual([3, 4, 5, 111]);\n\n    hook.rerender({ state: 5, capacity: 3, history: [1, 2, 3, 4, 5] });\n    expect(hook.result.current[0][2].capacity).toBe(4);\n    expect(hook.result.current[0][2].history).toEqual([3, 4, 5, 111]);\n\n    act(() => {\n      hook.result.current[0][1](() => 321);\n    });\n\n    expect(hook.result.current[0][0]).toBe(321);\n    expect(hook.result.current[0][2].capacity).toBe(3);\n    expect(hook.result.current[0][2].history).toEqual([5, 111, 321]);\n  });\n\n  describe('history.back()', () => {\n    it('should cause rerender', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      expect(hook.result.current[1]).toBe(1);\n      act(() => {\n        hook.result.current[0][2].back(1);\n      });\n      expect(hook.result.current[1]).toBe(2);\n    });\n\n    it('should travel history back one step at a time if called without arguments', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      expect(hook.result.current[0][0]).toBe(5);\n\n      act(() => {\n        hook.result.current[0][2].back();\n      });\n      expect(hook.result.current[0][0]).toBe(4);\n      act(() => {\n        hook.result.current[0][2].back();\n      });\n      expect(hook.result.current[0][0]).toBe(3);\n      act(() => {\n        hook.result.current[0][2].back();\n      });\n      expect(hook.result.current[0][0]).toBe(2);\n    });\n\n    it('should travel history back by arbitrary amount of elements passed as 1st argument', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      expect(hook.result.current[0][0]).toBe(5);\n\n      act(() => {\n        hook.result.current[0][2].back(2);\n      });\n      expect(hook.result.current[0][0]).toBe(3);\n\n      act(() => {\n        hook.result.current[0][2].back(3);\n      });\n      expect(hook.result.current[0][0]).toBe(1);\n    });\n\n    it('should stop on first element if traveled to the left border', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      expect(hook.result.current[0][0]).toBe(5);\n\n      act(() => {\n        hook.result.current[0][2].back(6);\n      });\n      expect(hook.result.current[0][0]).toBe(1);\n\n      act(() => {\n        hook.result.current[0][2].back(150);\n      });\n      expect(hook.result.current[0][0]).toBe(1);\n\n      act(() => {\n        hook.result.current[0][2].back();\n      });\n      expect(hook.result.current[0][0]).toBe(1);\n    });\n  });\n\n  describe('history.forward()', () => {\n    it('should cause rerender', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      act(() => {\n        hook.result.current[0][2].back(3);\n      });\n      expect(hook.result.current[1]).toBe(2);\n      act(() => {\n        hook.result.current[0][2].forward(1);\n      });\n      expect(hook.result.current[1]).toBe(3);\n    });\n\n    it('should travel history forward one step at a time if called without arguments', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      act(() => {\n        hook.result.current[0][2].back(6);\n      });\n      expect(hook.result.current[0][0]).toBe(1);\n\n      act(() => {\n        hook.result.current[0][2].forward();\n      });\n      expect(hook.result.current[0][0]).toBe(2);\n\n      act(() => {\n        hook.result.current[0][2].forward();\n      });\n      expect(hook.result.current[0][0]).toBe(3);\n    });\n\n    it('should travel history forward by arbitrary amount of elements passed as 1st argument', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      act(() => {\n        hook.result.current[0][2].back(6);\n      });\n      expect(hook.result.current[0][0]).toBe(1);\n\n      act(() => {\n        hook.result.current[0][2].forward(2);\n      });\n      expect(hook.result.current[0][0]).toBe(3);\n\n      act(() => {\n        hook.result.current[0][2].forward(2);\n      });\n      expect(hook.result.current[0][0]).toBe(5);\n    });\n\n    it('should stop on last element if traveled to the right border', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      act(() => {\n        hook.result.current[0][2].back(6);\n      });\n      expect(hook.result.current[0][0]).toBe(1);\n\n      act(() => {\n        hook.result.current[0][2].forward(7);\n      });\n      expect(hook.result.current[0][0]).toBe(5);\n\n      act(() => {\n        hook.result.current[0][2].forward(250);\n      });\n      expect(hook.result.current[0][0]).toBe(5);\n    });\n  });\n\n  describe('history.go()', () => {\n    it('should cause rerender', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      expect(hook.result.current[1]).toBe(1);\n      act(() => {\n        hook.result.current[0][2].go(1);\n      });\n      expect(hook.result.current[1]).toBe(2);\n    });\n\n    it('should go to arbitrary position passed as 1st element', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      act(() => {\n        hook.result.current[0][2].go(1);\n      });\n      expect(hook.result.current[0][0]).toBe(2);\n\n      act(() => {\n        hook.result.current[0][2].go(3);\n      });\n      expect(hook.result.current[0][0]).toBe(4);\n\n      act(() => {\n        hook.result.current[0][2].go(0);\n      });\n      expect(hook.result.current[0][0]).toBe(1);\n    });\n\n    it('should count from the right if position is negative', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      act(() => {\n        hook.result.current[0][2].go(-1);\n      });\n      expect(hook.result.current[0][0]).toBe(5);\n\n      act(() => {\n        hook.result.current[0][2].go(-3);\n      });\n      expect(hook.result.current[0][0]).toBe(3);\n\n      act(() => {\n        hook.result.current[0][2].go(-5);\n      });\n      expect(hook.result.current[0][0]).toBe(1);\n    });\n\n    it('should properly handle too big values', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      act(() => {\n        hook.result.current[0][2].go(-150);\n      });\n      expect(hook.result.current[0][0]).toBe(1);\n\n      act(() => {\n        hook.result.current[0][2].go(250);\n      });\n      expect(hook.result.current[0][0]).toBe(5);\n    });\n\n    it('should do nothing is position is equals current', () => {\n      const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n\n      act(() => {\n        hook.result.current[0][2].go(4);\n      });\n      expect(hook.result.current[1]).toBe(1);\n      expect(hook.result.current[0][0]).toBe(5);\n      expect(hook.result.current[1]).toBe(1);\n    });\n  });\n\n  it('should pop elements to the right when setting state being not in the end of history', () => {\n    const hook = getHook(5, 5, [1, 2, 3, 4, 5]);\n    act(() => {\n      hook.result.current[0][2].back(2);\n    });\n    expect(hook.result.current[0][2].history).toEqual([1, 2, 3, 4, 5]);\n    act(() => {\n      hook.result.current[0][1](8);\n    });\n    expect(hook.result.current[0][2].history).toEqual([1, 2, 3, 8]);\n  });\n\n  it('should throw if capacity is 0 or negative', () => {\n    let hook = getHook(3, -1);\n    expect(hook.result.error).toEqual(new Error(`Capacity has to be greater than 1, got '-1'`));\n\n    hook = getHook(3, 0);\n    expect(hook.result.error).toEqual(new Error(`Capacity has to be greater than 1, got '0'`));\n  });\n});\n"
  },
  {
    "path": "tests/useThrottle.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport useThrottle from '../src/useThrottle';\n\ndescribe('useThrottle', () => {\n  beforeAll(() => {\n    jest.useFakeTimers();\n  });\n\n  afterEach(() => {\n    jest.clearAllTimers();\n  });\n\n  afterAll(() => {\n    jest.useRealTimers();\n  });\n\n  it('should be defined', () => {\n    expect(useThrottle).toBeDefined();\n  });\n\n  it('should have a value to be returned', () => {\n    const { result } = renderHook(() => useThrottle(0, 100));\n    expect(result.current).toBe(0);\n  });\n\n  it('should has same value if time is advanced less than the given time', () => {\n    const { result, rerender } = renderHook((props) => useThrottle(props, 100), {\n      initialProps: 0,\n    });\n    expect(result.current).toBe(0);\n    rerender(1);\n    jest.advanceTimersByTime(50);\n    expect(result.current).toBe(0);\n  });\n\n  it('should update the value after the given time when prop change', (done) => {\n    const hook = renderHook((props) => useThrottle(props, 100), { initialProps: 0 });\n    expect(hook.result.current).toBe(0);\n    hook.rerender(1);\n    expect(hook.result.current).toBe(0);\n    hook.waitForNextUpdate().then(() => {\n      expect(hook.result.current).toBe(1);\n      done();\n    });\n    jest.advanceTimersByTime(100);\n  });\n\n  it('should use the default ms value when missing', (done) => {\n    const hook = renderHook((props) => useThrottle(props), { initialProps: 0 });\n    expect(hook.result.current).toBe(0);\n    hook.rerender(1);\n    hook.waitForNextUpdate().then(() => {\n      expect(hook.result.current).toBe(1);\n      done();\n    });\n    jest.advanceTimersByTime(200);\n  });\n\n  it('should not update the value after the given time', () => {\n    const hook = renderHook((props) => useThrottle(props, 100), { initialProps: 0 });\n    expect(hook.result.current).toBe(0);\n    jest.advanceTimersByTime(100);\n    expect(hook.result.current).toBe(0);\n  });\n\n  it('should cancel timeout on unmount', () => {\n    const hook = renderHook((props) => useThrottle(props, 100), { initialProps: 0 });\n    expect(hook.result.current).toBe(0);\n    hook.rerender(1);\n    hook.unmount();\n    expect(jest.getTimerCount()).toBe(0);\n    jest.advanceTimersByTime(100);\n    expect(hook.result.current).toBe(0);\n  });\n});\n"
  },
  {
    "path": "tests/useThrottleFn.test.ts",
    "content": "import { renderHook, RenderHookResult } from '@testing-library/react-hooks';\nimport { useThrottleFn } from '../src';\n\ndescribe('useThrottleFn', () => {\n  beforeAll(() => {\n    jest.useFakeTimers();\n  });\n  afterAll(() => {\n    jest.useRealTimers();\n  });\n  afterEach(() => {\n    jest.clearAllTimers();\n  });\n\n  it('should be defined', () => {\n    expect(useThrottleFn).toBeDefined();\n  });\n\n  const getHook = <T>(initialProps: T, ms?: number): [Function, RenderHookResult<T, T>] => {\n    const mockFn = jest.fn((props) => props);\n    return [mockFn, renderHook((props) => useThrottleFn(mockFn, ms, [props]), { initialProps })];\n  };\n\n  it('should return the value that the given function return', () => {\n    const [fn, hook] = getHook(10, 100);\n\n    expect(hook.result.current).toBe(10);\n    expect(fn).toHaveBeenCalledTimes(1);\n  });\n\n  it('should has same value if time is advanced less than the given time', () => {\n    const [fn, hook] = getHook(10, 100);\n\n    expect(hook.result.current).toBe(10);\n    expect(fn).toHaveBeenCalledTimes(1);\n\n    hook.rerender(20);\n    jest.advanceTimersByTime(50);\n\n    expect(hook.result.current).toBe(10);\n    expect(fn).toHaveBeenCalledTimes(1);\n    expect(jest.getTimerCount()).toBe(1);\n  });\n\n  it('should update the value after the given time when arguments change', (done) => {\n    const [fn, hook] = getHook('boo', 100);\n\n    expect(hook.result.current).toBe('boo');\n    expect(fn).toHaveBeenCalledTimes(1);\n\n    hook.rerender('foo');\n    hook.waitForNextUpdate().then(() => {\n      expect(hook.result.current).toBe('foo');\n      expect(fn).toHaveBeenCalledTimes(2);\n      done();\n    });\n    jest.advanceTimersByTime(100);\n  });\n\n  it('should use the default ms value when missing', (done) => {\n    const [fn, hook] = getHook('boo');\n\n    expect(hook.result.current).toBe('boo');\n    expect(fn).toHaveBeenCalledTimes(1);\n\n    hook.rerender('foo');\n    hook.waitForNextUpdate().then(() => {\n      expect(hook.result.current).toBe('foo');\n      expect(fn).toHaveBeenCalledTimes(2);\n      done();\n    });\n    jest.advanceTimersByTime(200);\n  });\n  it('should not exist timer when arguments did not update after the given time', () => {\n    const [fn, hook] = getHook('boo', 100);\n\n    expect(hook.result.current).toBe('boo');\n    expect(fn).toHaveBeenCalledTimes(1);\n    expect(jest.getTimerCount()).toBe(1);\n\n    jest.advanceTimersByTime(100);\n\n    expect(jest.getTimerCount()).toBe(0);\n  });\n  it('should cancel timeout on unmount', () => {\n    const [fn, hook] = getHook('boo', 100);\n\n    expect(hook.result.current).toBe('boo');\n    expect(fn).toHaveBeenCalledTimes(1);\n\n    hook.rerender('foo');\n    hook.unmount();\n\n    expect(jest.getTimerCount()).toBe(0);\n    jest.advanceTimersByTime(100);\n    expect(fn).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "tests/useTimeout.test.ts",
    "content": "import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks';\nimport { useTimeout } from '../src';\nimport { UseTimeoutReturn } from '../src/useTimeout';\n\nbeforeAll(() => {\n  jest.useFakeTimers();\n});\n\nafterEach(() => {\n  jest.clearAllTimers();\n});\n\nafterAll(() => {\n  jest.useRealTimers();\n});\n\nit('should be defined', () => {\n  expect(useTimeout).toBeDefined();\n});\n\nit('should return three functions', () => {\n  const hook = renderHook(() => useTimeout(5));\n\n  expect(hook.result.current.length).toBe(3);\n  expect(typeof hook.result.current[0]).toBe('function');\n  expect(typeof hook.result.current[1]).toBe('function');\n  expect(typeof hook.result.current[2]).toBe('function');\n});\n\nfunction getHook(\n  ms: number = 5\n): [jest.Mock, RenderHookResult<{ delay: number }, UseTimeoutReturn>] {\n  const spy = jest.fn();\n  return [\n    spy,\n    renderHook(\n      ({ delay = 5 }) => {\n        spy();\n        return useTimeout(delay);\n      },\n      { initialProps: { delay: ms } }\n    ),\n  ];\n}\n\nit('should re-render component after given amount of time', (done) => {\n  const [spy, hook] = getHook();\n  expect(spy).toHaveBeenCalledTimes(1);\n  hook.waitForNextUpdate().then(() => {\n    expect(spy).toHaveBeenCalledTimes(2);\n    done();\n  });\n  jest.advanceTimersByTime(5);\n});\n\nit('should cancel timeout on unmount', () => {\n  const [spy, hook] = getHook();\n\n  expect(spy).toHaveBeenCalledTimes(1);\n  hook.unmount();\n  jest.advanceTimersByTime(5);\n  expect(spy).toHaveBeenCalledTimes(1);\n});\n\nit('first function should return actual state of timeout', (done) => {\n  let [, hook] = getHook();\n  let [isReady] = hook.result.current;\n\n  expect(isReady()).toBe(false);\n  hook.unmount();\n  expect(isReady()).toBe(null);\n\n  [, hook] = getHook();\n  [isReady] = hook.result.current;\n  hook.waitForNextUpdate().then(() => {\n    expect(isReady()).toBe(true);\n\n    done();\n  });\n  jest.advanceTimersByTime(5);\n});\n\nit('second function should cancel timeout', () => {\n  const [spy, hook] = getHook();\n  const [isReady, cancel] = hook.result.current;\n\n  expect(spy).toHaveBeenCalledTimes(1);\n  expect(isReady()).toBe(false);\n\n  act(() => {\n    cancel();\n  });\n  jest.advanceTimersByTime(5);\n\n  expect(spy).toHaveBeenCalledTimes(1);\n  expect(isReady()).toBe(null);\n});\n\nit('third function should reset timeout', (done) => {\n  const [spy, hook] = getHook();\n  const [isReady, cancel, reset] = hook.result.current;\n\n  expect(isReady()).toBe(false);\n\n  act(() => {\n    cancel();\n  });\n  jest.advanceTimersByTime(5);\n\n  expect(isReady()).toBe(null);\n\n  act(() => {\n    reset();\n  });\n  expect(isReady()).toBe(false);\n\n  hook.waitForNextUpdate().then(() => {\n    expect(spy).toHaveBeenCalledTimes(2);\n    expect(isReady()).toBe(true);\n\n    done();\n  });\n  jest.advanceTimersByTime(5);\n});\n\nit('should reset timeout on delay change', (done) => {\n  const [spy, hook] = getHook(15);\n\n  expect(spy).toHaveBeenCalledTimes(1);\n  hook.rerender({ delay: 5 });\n\n  hook.waitForNextUpdate().then(() => {\n    expect(spy).toHaveBeenCalledTimes(3);\n\n    done();\n  });\n  jest.advanceTimersByTime(15);\n});\n"
  },
  {
    "path": "tests/useTimeoutFn.test.ts",
    "content": "import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks';\nimport { useTimeoutFn } from '../src';\nimport { UseTimeoutFnReturn } from '../src/useTimeoutFn';\n\ndescribe('useTimeoutFn', () => {\n  beforeAll(() => {\n    jest.useFakeTimers();\n  });\n\n  afterEach(() => {\n    jest.clearAllTimers();\n  });\n\n  afterAll(() => {\n    jest.useRealTimers();\n  });\n\n  it('should be defined', () => {\n    expect(useTimeoutFn).toBeDefined();\n  });\n\n  it('should return three functions', () => {\n    const hook = renderHook(() => useTimeoutFn(() => {}, 5));\n\n    expect(hook.result.current.length).toBe(3);\n    expect(typeof hook.result.current[0]).toBe('function');\n    expect(typeof hook.result.current[1]).toBe('function');\n    expect(typeof hook.result.current[2]).toBe('function');\n  });\n\n  function getHook(\n    ms: number = 5,\n    fn: Function = jest.fn()\n  ): [Function, RenderHookResult<{ delay: number; cb: Function }, UseTimeoutFnReturn>] {\n    return [\n      fn,\n      renderHook(({ delay = 5, cb }) => useTimeoutFn(cb, delay), {\n        initialProps: { delay: ms, cb: fn },\n      }),\n    ];\n  }\n\n  it('should call passed function after given amount of time', () => {\n    const [spy] = getHook();\n\n    expect(spy).not.toHaveBeenCalled();\n    jest.advanceTimersByTime(5);\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n\n  it('should cancel function call on unmount', () => {\n    const [spy, hook] = getHook();\n\n    expect(spy).not.toHaveBeenCalled();\n    hook.unmount();\n    jest.advanceTimersByTime(5);\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('first function should return actual state of timeout', () => {\n    let [, hook] = getHook();\n    let [isReady] = hook.result.current;\n\n    expect(isReady()).toBe(false);\n    hook.unmount();\n    expect(isReady()).toBe(null);\n\n    [, hook] = getHook();\n    [isReady] = hook.result.current;\n    jest.advanceTimersByTime(5);\n    expect(isReady()).toBe(true);\n  });\n\n  it('second function should cancel timeout', () => {\n    const [spy, hook] = getHook();\n    const [isReady, cancel] = hook.result.current;\n\n    expect(spy).not.toHaveBeenCalled();\n    expect(isReady()).toBe(false);\n\n    act(() => {\n      cancel();\n    });\n    jest.advanceTimersByTime(5);\n\n    expect(spy).not.toHaveBeenCalled();\n    expect(isReady()).toBe(null);\n  });\n\n  it('third function should reset timeout', () => {\n    const [spy, hook] = getHook();\n    const [isReady, cancel, reset] = hook.result.current;\n\n    expect(isReady()).toBe(false);\n\n    act(() => {\n      cancel();\n    });\n    jest.advanceTimersByTime(5);\n\n    expect(isReady()).toBe(null);\n\n    act(() => {\n      reset();\n    });\n    expect(isReady()).toBe(false);\n\n    jest.advanceTimersByTime(5);\n\n    expect(spy).toHaveBeenCalledTimes(1);\n    expect(isReady()).toBe(true);\n  });\n\n  it('should reset timeout on delay change', () => {\n    const [spy, hook] = getHook(50);\n\n    expect(spy).not.toHaveBeenCalled();\n    hook.rerender({ delay: 5, cb: spy });\n\n    jest.advanceTimersByTime(5);\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n\n  it('should NOT reset timeout on function change', () => {\n    const [spy, hook] = getHook(50);\n\n    jest.advanceTimersByTime(25);\n    expect(spy).not.toHaveBeenCalled();\n\n    const spy2 = jest.fn();\n    hook.rerender({ delay: 50, cb: spy2 });\n\n    jest.advanceTimersByTime(25);\n    expect(spy).not.toHaveBeenCalled();\n    expect(spy2).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "tests/useTitle.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport useTitle from '../src/useTitle';\n\ndescribe('useTitle', () => {\n  it('should be defined', () => {\n    expect(useTitle).toBeDefined();\n  });\n\n  it('should update document title', () => {\n    const hook = renderHook((props) => useTitle(props), { initialProps: 'My page title' });\n\n    expect(document.title).toBe('My page title');\n    hook.rerender('My other page title');\n    expect(document.title).toBe('My other page title');\n  });\n\n  it('should restore document title on unmount', () => {\n    renderHook((props) => useTitle(props), { initialProps: 'Old Title' });\n    expect(document.title).toBe('Old Title');\n\n    const hook = renderHook((props) => useTitle(props.title, { restoreOnUnmount: props.restore }), {\n      initialProps: { title: 'New Title', restore: true },\n    });\n    expect(document.title).toBe('New Title');\n    hook.unmount();\n    expect(document.title).toBe('Old Title');\n  });\n});\n"
  },
  {
    "path": "tests/useToggle.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useToggle from '../src/useToggle';\n\nconst setUp = (initialValue: boolean) => renderHook(() => useToggle(initialValue));\n\nit('should init state to true', () => {\n  const { result } = setUp(true);\n\n  expect(result.current[0]).toBe(true);\n  expect(typeof result.current[1]).toBe('function');\n});\n\nit('should init state to false', () => {\n  const { result } = setUp(false);\n\n  expect(result.current[0]).toBe(false);\n  expect(result.current[1]).toBeInstanceOf(Function);\n});\n\nit('should set state to true', () => {\n  const { result } = setUp(false);\n  const [, toggle] = result.current;\n\n  expect(result.current[0]).toBe(false);\n\n  act(() => {\n    toggle(true);\n  });\n\n  expect(result.current[0]).toBe(true);\n});\n\nit('should set state to false', () => {\n  const { result } = setUp(true);\n  const [, toggle] = result.current;\n\n  expect(result.current[0]).toBe(true);\n\n  act(() => {\n    toggle(false);\n  });\n\n  expect(result.current[0]).toBe(false);\n});\n\nit('should toggle state from true', () => {\n  const { result } = setUp(true);\n  const [, toggle] = result.current;\n\n  act(() => {\n    toggle();\n  });\n\n  expect(result.current[0]).toBe(false);\n});\n\nit('should toggle state from false', () => {\n  const { result } = setUp(false);\n  const [, toggle] = result.current;\n\n  act(() => {\n    toggle();\n  });\n\n  expect(result.current[0]).toBe(true);\n});\n\nit('should ignore non-boolean parameters and toggle state', () => {\n  const { result } = setUp(true);\n  const [, toggle] = result.current;\n\n  act(() => {\n    toggle('string');\n  });\n\n  expect(result.current[0]).toBe(false);\n\n  act(() => {\n    toggle({});\n  });\n\n  expect(result.current[0]).toBe(true);\n});\n"
  },
  {
    "path": "tests/useTween.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { easing } from 'ts-easing';\nimport * as useRaf from '../src/useRaf';\nimport useTween from '../src/useTween';\n\nlet spyUseRaf;\nlet spyEasingInCirc;\nlet spyEasingOutCirc;\n\nbeforeEach(() => {\n  spyUseRaf = jest.spyOn(useRaf, 'default').mockReturnValue(17);\n  spyEasingInCirc = jest.spyOn(easing, 'inCirc').mockReturnValue(999999);\n  spyEasingOutCirc = jest.spyOn(easing, 'outCirc').mockReturnValue(101010);\n});\n\nafterEach(() => {\n  jest.restoreAllMocks();\n});\n\nit('should init corresponding utils with default values', () => {\n  const { result } = renderHook(() => useTween());\n\n  expect(result.current).toBe(999999);\n  expect(spyEasingInCirc).toHaveBeenCalledTimes(1);\n  expect(spyEasingInCirc).toHaveBeenCalledWith(17);\n  expect(spyUseRaf).toHaveBeenCalledTimes(1);\n  expect(spyUseRaf).toHaveBeenCalledWith(200, 0);\n});\n\nit('should init corresponding utils with custom values', () => {\n  const { result } = renderHook(() => useTween('outCirc', 500, 15));\n\n  expect(result.current).toBe(101010);\n  expect(spyEasingOutCirc).toHaveBeenCalledTimes(1);\n  expect(spyEasingOutCirc).toHaveBeenCalledWith(17);\n  expect(spyUseRaf).toHaveBeenCalledTimes(1);\n  expect(spyUseRaf).toHaveBeenCalledWith(500, 15);\n});\n\ndescribe('when invalid easing name is provided', () => {\n  beforeEach(() => {\n    jest.spyOn(console, 'error').mockImplementation(() => {});\n    jest.spyOn(console, 'trace').mockImplementation(() => {});\n  });\n\n  it('should log an error', () => {\n    const { result } = renderHook(() => useTween('grijanderl'));\n\n    expect(result.current).toBe(0);\n    expect(console.error).toHaveBeenCalledTimes(1);\n    expect(console.error).toHaveBeenCalledWith(\n      expect.stringContaining(\n        'useTween() expected \"easingName\" property to be a valid easing function name'\n      )\n    );\n    expect(console.trace).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "tests/useUnmount.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useUnmount } from '../src';\n\ndescribe('useUnmount', () => {\n  it('should be defined', () => {\n    expect(useUnmount).toBeDefined();\n  });\n\n  it('should not call provided callback on mount', () => {\n    const spy = jest.fn();\n    renderHook(() => useUnmount(spy));\n\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('should not call provided callback on re-renders', () => {\n    const spy = jest.fn();\n    const hook = renderHook(() => useUnmount(spy));\n\n    hook.rerender();\n    hook.rerender();\n    hook.rerender();\n    hook.rerender();\n\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('should call provided callback on unmount', () => {\n    const spy = jest.fn();\n    const hook = renderHook(() => useUnmount(spy));\n\n    hook.unmount();\n\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n\n  it('should call provided callback if is has been changed', () => {\n    const spy = jest.fn();\n    const spy2 = jest.fn();\n    const spy3 = jest.fn();\n    const hook = renderHook((cb) => useUnmount(cb), { initialProps: spy });\n\n    hook.rerender(spy2);\n    hook.rerender(spy3);\n    hook.unmount();\n\n    expect(spy).not.toHaveBeenCalled();\n    expect(spy2).not.toHaveBeenCalled();\n    expect(spy3).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "tests/useUnmountPromise.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport useUnmountPromise from '../src/useUnmountPromise';\n\ndescribe('useUnmountPromise', () => {\n  it('should be defined', () => {\n    expect(useUnmountPromise).toBeDefined();\n  });\n\n  it('should return a function', () => {\n    const hook = renderHook(() => useUnmountPromise());\n\n    expect(typeof hook.result.current).toBe('function');\n  });\n\n  it('when component is mounted function should resolve with wrapped promises', async () => {\n    const hook = renderHook(() => useUnmountPromise());\n\n    const mounted = hook.result.current;\n    const res = await mounted(new Promise((r) => setTimeout(() => r(25), 10)));\n\n    expect(res).toBe(25);\n  });\n\n  it('when component is unmounted promise never resolves', async () => {\n    const hook = renderHook(() => useUnmountPromise());\n\n    const mounted = hook.result.current;\n    const promise = mounted(new Promise((r) => setTimeout(() => r(25), 10)));\n\n    hook.unmount();\n\n    const res = await Promise.race([\n      promise,\n      new Promise((r) => setTimeout(() => r('UNMOUNTED'), 20)),\n    ]);\n    expect(res).toBe('UNMOUNTED');\n  });\n\n  it('should resolve promise when component is updated', async () => {\n    const hook = renderHook(() => useUnmountPromise());\n\n    const mounted = hook.result.current;\n    const pRes = mounted(new Promise((r) => setTimeout(() => r(25), 10)));\n\n    hook.rerender();\n\n    const res = await pRes;\n\n    expect(res).toBe(25);\n  });\n\n  it('when component is mounted function should resolve with wrapped promises - 2', async () => {\n    const hook = renderHook(() => useUnmountPromise());\n\n    const mounted = hook.result.current;\n    const promise = mounted(new Promise((r) => setTimeout(() => r(25), 10)));\n\n    // hook.unmount();\n\n    const res = await Promise.race([\n      promise,\n      new Promise((r) => setTimeout(() => r('UNMOUNTED'), 20)),\n    ]);\n    expect(res).toBe(25);\n  });\n\n  describe('when promise throws', () => {\n    describe('when component is mounted', () => {\n      it('onError callback is not called', async () => {\n        const hook = renderHook(() => useUnmountPromise());\n\n        const mounted = hook.result.current;\n        const onError = jest.fn();\n        try {\n          await mounted(new Promise((r, reject) => setTimeout(() => reject(r), 10)), onError);\n        } catch {}\n\n        expect(onError).toHaveBeenCalledTimes(0);\n      });\n    });\n\n    describe('when component is un-mounted', () => {\n      it('onError callback is called', async () => {\n        const hook = renderHook(() => useUnmountPromise());\n\n        const mounted = hook.result.current;\n        const onError = jest.fn();\n        const promise = mounted(\n          new Promise((r, reject) => setTimeout(() => reject(r), 10)),\n          onError\n        );\n\n        hook.unmount();\n        await Promise.race([promise, new Promise((r) => setTimeout(r, 20))]);\n\n        expect(onError).toHaveBeenCalledTimes(1);\n        expect(typeof onError.mock.calls[0][0]).toBe('function');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/useUpdate.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useUpdate from '../src/useUpdate';\n\ndescribe('useUpdate', () => {\n  it('should be defined', () => {\n    expect(useUpdate).toBeDefined();\n  });\n\n  it('should return a function', () => {\n    const { result } = renderHook(() => useUpdate());\n\n    expect(typeof result.current).toBe('function');\n  });\n\n  it('should re-render component each time returned function is called', () => {\n    let renders = 0;\n    const {\n      result: { current: update },\n    } = renderHook(() => {\n      renders++;\n      return useUpdate();\n    });\n\n    expect(renders).toBe(1);\n\n    act(() => update());\n    expect(renders).toBe(2);\n\n    act(() => update());\n    expect(renders).toBe(3);\n  });\n\n  it('should return exact same function in between renders', () => {\n    let renders = 0;\n    const { result } = renderHook(() => {\n      renders++;\n      return useUpdate();\n    });\n    let initialUpdateFn = result.current;\n\n    expect(renders).toBe(1);\n\n    act(() => result.current());\n    expect(renders).toBe(2);\n    expect(initialUpdateFn).toBe(result.current);\n\n    act(() => result.current());\n    expect(renders).toBe(3);\n    expect(initialUpdateFn).toBe(result.current);\n  });\n\n  it('passing the argument to returned function should not affect the use', () => {\n    let renders = 0;\n    const { result } = renderHook(() => {\n      renders++;\n      return useUpdate();\n    });\n    let initialUpdateFn = result.current;\n\n    expect(renders).toBe(1);\n\n    /* @ts-expect-error */\n    act(() => result.current(1));\n    expect(renders).toBe(2);\n    expect(initialUpdateFn).toBe(result.current);\n\n    /* @ts-expect-error */\n    act(() => result.current(1));\n    expect(renders).toBe(3);\n    expect(initialUpdateFn).toBe(result.current);\n  });\n});\n"
  },
  {
    "path": "tests/useUpdateEffect.test.ts",
    "content": "import { renderHook } from '@testing-library/react-hooks';\nimport { useUpdateEffect } from '../src';\n\nit('should run effect on update', () => {\n  const effect = jest.fn();\n\n  const { rerender } = renderHook(() => useUpdateEffect(effect));\n  expect(effect).not.toHaveBeenCalled();\n\n  rerender();\n  expect(effect).toHaveBeenCalledTimes(1);\n});\n\nit('should run cleanup on unmount', () => {\n  const cleanup = jest.fn();\n  const effect = jest.fn().mockReturnValue(cleanup);\n  const hook = renderHook(() => useUpdateEffect(effect));\n\n  hook.rerender();\n  hook.unmount();\n\n  expect(cleanup).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "tests/useUpsert.test.ts",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport useUpsert from '../src/useUpsert';\n\ninterface TestItem {\n  id: string;\n  text: string;\n}\n\nconst testItems: TestItem[] = [\n  { id: '1', text: '1' },\n  { id: '2', text: '2' },\n];\n\nconst itemsAreEqual = (a: TestItem, b: TestItem) => {\n  return a.id === b.id;\n};\n\nconst setUp = (initialList: TestItem[] = []) =>\n  renderHook(() => useUpsert<TestItem>(itemsAreEqual, initialList));\n\ndescribe('useUpsert', () => {\n  describe('initialization', () => {\n    const { result } = setUp(testItems);\n    const [list, utils] = result.current;\n\n    it('properly initiates the list content', () => {\n      expect(list).toEqual(testItems);\n    });\n\n    it('returns an upsert function', () => {\n      expect(utils.upsert).toBeInstanceOf(Function);\n    });\n  });\n\n  describe('upserting a new item', () => {\n    const { result } = setUp(testItems);\n    const [, utils] = result.current;\n\n    const newItem: TestItem = {\n      id: '3',\n      text: '3',\n    };\n    act(() => {\n      utils.upsert(newItem);\n    });\n\n    it('inserts a new item', () => {\n      expect(result.current[0]).toContain(newItem);\n    });\n    it('works immutably', () => {\n      expect(result.current[0]).not.toBe(testItems);\n    });\n  });\n\n  describe('upserting an existing item', () => {\n    const { result } = setUp(testItems);\n    const [, utils] = result.current;\n\n    const newItem: TestItem = {\n      id: '2',\n      text: '4',\n    };\n    act(() => {\n      utils.upsert(newItem);\n    });\n    const updatedList = result.current[0];\n\n    it('has the same length', () => {\n      expect(updatedList).toHaveLength(testItems.length);\n    });\n    it('updates the item', () => {\n      expect(updatedList).toContain(newItem);\n    });\n    it('works immutably', () => {\n      expect(updatedList).not.toBe(testItems);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/useWindowScroll.test.tsx",
    "content": "import React, { useEffect } from 'react';\nimport { render, act as reactAct } from '@testing-library/react';\nimport { act, renderHook } from '@testing-library/react-hooks';\nimport { replaceRaf } from 'raf-stub';\n\nimport useWindowScroll from '../src/useWindowScroll';\n\ndeclare var requestAnimationFrame: {\n  reset: () => void;\n  step: (steps?: number, duration?: number) => void;\n};\n\ndescribe('useWindowScroll', () => {\n  beforeAll(() => {\n    replaceRaf();\n  });\n\n  afterEach(() => {\n    requestAnimationFrame.reset();\n  });\n\n  it('should be defined', () => {\n    expect(useWindowScroll).toBeDefined();\n  });\n\n  function getHook() {\n    return renderHook(() => {\n      return useWindowScroll();\n    });\n  }\n\n  function setWindowScroll(x: number, y: number) {\n    (window.pageXOffset as number) = x;\n    (window.pageYOffset as number) = y;\n  }\n\n  function triggerScroll(dimension: 'x' | 'y', value: number) {\n    if (dimension === 'x') {\n      (window.pageXOffset as number) = value;\n    } else if (dimension === 'y') {\n      (window.pageYOffset as number) = value;\n    }\n\n    window.dispatchEvent(new Event('scroll'));\n  }\n\n  it('should return window scroll value at mount time', () => {\n    setWindowScroll(1, 2);\n\n    const hook = getHook();\n\n    expect(hook.result.current).toEqual({\n      x: 1,\n      y: 2,\n    });\n  });\n\n  it('should re-render after X scroll change on closest RAF', () => {\n    setWindowScroll(1, 2);\n    const hook = getHook();\n\n    act(() => {\n      triggerScroll('x', 100);\n      expect(hook.result.current.x).toBe(1);\n\n      requestAnimationFrame.step();\n    });\n\n    expect(hook.result.current.x).toBe(100);\n\n    act(() => {\n      triggerScroll('x', 1000);\n      expect(hook.result.current.x).toBe(100);\n      requestAnimationFrame.step();\n    });\n\n    expect(hook.result.current.x).toBe(1000);\n  });\n\n  it('should re-render after Y scroll change on closest RAF', () => {\n    setWindowScroll(1, 2);\n    const hook = getHook();\n\n    act(() => {\n      triggerScroll('y', 200);\n      expect(hook.result.current.y).toBe(2);\n      requestAnimationFrame.step();\n    });\n\n    expect(hook.result.current.y).toBe(200);\n\n    act(() => {\n      triggerScroll('y', 300);\n      expect(hook.result.current.y).toBe(200);\n      requestAnimationFrame.step();\n    });\n\n    expect(hook.result.current.y).toBe(300);\n  });\n\n  it('should set window scroll in mount effect, just before subscription, to prevent losing scroll change between render and mount', () => {\n    const initialScroll = { x: 1, y: 2 };\n    const afterRenderScroll = { x: 2, y: 3 };\n    const result = {\n      x: 0,\n      y: 0,\n    };\n\n    setWindowScroll(initialScroll.x, initialScroll.y);\n\n    const TestComponent = () => {\n      useEffect(() => {\n        // Simulate window scroll changing between component render and useWindowScroll effect handler,\n        // before adding the event listener\n        setWindowScroll(afterRenderScroll.x, afterRenderScroll.y);\n      }, []);\n\n      const { x, y } = useWindowScroll();\n      result.x = x;\n      result.y = y;\n      return <div />;\n    };\n\n    const { rerender } = render(<TestComponent />);\n    rerender(<TestComponent />);\n\n    //result update is delayed by requestAnimationFrame\n    expect(result).toEqual(initialScroll);\n\n    reactAct(() => {\n      requestAnimationFrame.step();\n    });\n\n    //result is updated next requestAnimationFrame\n    expect(result).toEqual(afterRenderScroll);\n  });\n});\n"
  },
  {
    "path": "tests/useWindowSize.test.tsx",
    "content": "import { act, renderHook } from '@testing-library/react-hooks';\nimport { replaceRaf } from 'raf-stub';\nimport useWindowSize from '../src/useWindowSize';\nimport { isBrowser } from '../src/misc/util';\n\ndeclare var requestAnimationFrame: {\n  reset: () => void;\n  step: (steps?: number, duration?: number) => void;\n};\n\ndescribe('useWindowSize', () => {\n  beforeAll(() => {\n    replaceRaf();\n  });\n\n  afterEach(() => {\n    requestAnimationFrame.reset();\n  });\n\n  it('should be defined', () => {\n    expect(useWindowSize).toBeDefined();\n  });\n\n  function getHook(options?: any) {\n    return renderHook(() => useWindowSize(options));\n  }\n\n  function triggerResize(dimension: 'width' | 'height', value: number) {\n    if (dimension === 'width') {\n      (window.innerWidth as number) = value;\n    } else if (dimension === 'height') {\n      (window.innerHeight as number) = value;\n    }\n\n    window.dispatchEvent(new Event('resize'));\n  }\n\n  it('should return current window dimensions', () => {\n    const hook = getHook();\n\n    expect(typeof hook.result.current).toBe('object');\n    expect(typeof hook.result.current.height).toBe('number');\n    expect(typeof hook.result.current.width).toBe('number');\n  });\n\n  it('should use passed parameters as initial values in case of non-browser use', () => {\n    const hook = getHook({ initialWidth: 1, initialHeight: 1 });\n\n    expect(hook.result.current.height).toBe(isBrowser ? window.innerHeight : 1);\n    expect(hook.result.current.width).toBe(isBrowser ? window.innerWidth : 1);\n  });\n\n  it('should re-render after height change on closest RAF', () => {\n    const hook = getHook();\n\n    act(() => {\n      triggerResize('height', 360);\n      requestAnimationFrame.step();\n    });\n\n    expect(hook.result.current.height).toBe(360);\n\n    act(() => {\n      triggerResize('height', 2048);\n      requestAnimationFrame.step();\n    });\n\n    expect(hook.result.current.height).toBe(2048);\n  });\n\n  it('should re-render after width change on closest RAF', () => {\n    const hook = getHook();\n\n    act(() => {\n      triggerResize('width', 360);\n      requestAnimationFrame.step();\n    });\n\n    expect(hook.result.current.width).toBe(360);\n\n    act(() => {\n      triggerResize('width', 2048);\n      requestAnimationFrame.step();\n    });\n\n    expect(hook.result.current.width).toBe(2048);\n  });\n\n  it('should call onChange callback on window resize', () => {\n    const onChange = jest.fn();\n    getHook({ onChange });\n\n    act(() => {\n      triggerResize('width', 720);\n      triggerResize('height', 480);\n      requestAnimationFrame.step();\n    });\n\n    expect(onChange).toHaveBeenCalledWith(720, 480);\n    expect(onChange).toHaveBeenCalledTimes(2);\n\n    act(() => {\n      triggerResize('width', 1920);\n      triggerResize('height', 1080);\n      requestAnimationFrame.step();\n    });\n\n    expect(onChange).toHaveBeenCalledWith(1920, 1080);\n    expect(onChange).toHaveBeenCalledTimes(4);\n  });\n});\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"jsx\": \"react\",\n    \"declaration\": true,\n    \"pretty\": true,\n    \"rootDir\": \"src\",\n    \"sourceMap\": false,\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitAny\": false,\n    \"noFallthroughCasesInSwitch\": true,\n    \"outDir\": \"lib\",\n    \"lib\": [\n      \"es2018\",\n      \"dom\"\n    ],\n    \"importHelpers\": true\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"lib\",\n    \"esm\",\n    \"tests\",\n    \"stories\",\n    \"jest.config.ts\",\n    \"jest.config.*.ts\"\n  ]\n}\n"
  }
]