[
  {
    "path": ".all-contributorsrc",
    "content": "{\n  \"files\": [\n    \"README.md\"\n  ],\n  \"imageSize\": 100,\n  \"commit\": false,\n  \"contributors\": [\n    {\n      \"login\": \"wellyshen\",\n      \"name\": \"Welly\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/21308003?v=4\",\n      \"profile\": \"http://wellyshen.com\",\n      \"contributions\": [\n        \"ideas\",\n        \"code\",\n        \"doc\",\n        \"infra\",\n        \"maintenance\"\n      ]\n    },\n    {\n      \"login\": \"Chris-James\",\n      \"name\": \"Chris\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/4596428?v=4\",\n      \"profile\": \"https://github.com/Chris-James\",\n      \"contributions\": [\n        \"bug\"\n      ]\n    }\n  ],\n  \"contributorsPerLine\": 7,\n  \"projectName\": \"react-cool-form\",\n  \"projectOwner\": \"wellyshen\",\n  \"repoType\": \"github\",\n  \"repoHost\": \"https://github.com\",\n  \"skipCi\": true\n}\n"
  },
  {
    "path": ".changeset/README.md",
    "content": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works\nwith multi-package repos, or single-package repos to help you version and publish your code. You can\nfind the full documentation for it [in our repository](https://github.com/changesets/changesets)\n\nWe have a quick list of common questions to get you started engaging with this project in\n[our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md)\n"
  },
  {
    "path": ".changeset/config.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@1.7.0/schema.json\",\n  \"changelog\": [\n    \"@changesets/changelog-github\",\n    { \"repo\": \"wellyshen/react-cool-form\" }\n  ],\n  \"commit\": false,\n  \"linked\": [],\n  \"access\": \"public\",\n  \"baseBranch\": \"master\",\n  \"updateInternalDependencies\": \"patch\",\n  \"ignore\": []\n}\n"
  },
  {
    "path": ".eslintignore",
    "content": "dist\nscripts/rollup\napp\nexamples\nwebsite"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  extends: [\"welly\"],\n  rules: {\n    eqeqeq: \"off\",\n    camelcase: \"off\",\n    \"no-shadow\": \"off\",\n    \"no-console\": [\n      \"warn\",\n      {\n        allow: [\"warn\", \"error\"],\n      },\n    ],\n    \"no-param-reassign\": \"off\",\n    \"no-underscore-dangle\": \"off\",\n    \"no-sparse-arrays\": \"off\",\n    \"no-restricted-syntax\": \"off\",\n    \"react/react-in-jsx-scope\": \"off\",\n    \"react/require-default-props\": \"off\",\n    \"@typescript-eslint/ban-types\": \"off\",\n    \"@typescript-eslint/no-non-null-assertion\": \"off\",\n    \"testing-library/render-result-naming-convention\": \"off\",\n  },\n  settings: {\n    polyfills: [\"Promise\"],\n  },\n};\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: react-cool-form\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: \"\\U0001F41B Bug Report\"\nabout: Create a report to help us improve\ntitle: \"\"\nlabels: \"\"\nassignees: \"\"\n---\n\n# Bug Report\n\n## Describe the Bug\n\nA clear and concise description of what the bug is.\n\n## How to Reproduce\n\nSteps to reproduce the behavior, please provide code snippets or a repository:\n\n1. Go to '....'\n2. Click on '....'\n3. See error\n\n## CodeSandbox Link\n\nShow me the bug on [CodeSandbox](https://codesandbox.io).\n\n## Expected Behavior\n\nTell me what should happen.\n\n## Screenshots\n\nAdd screenshots to help explain your problem.\n\n## Your Environment\n\n- Device: [e.g. MacBook Pro, iPhone12]\n- OS: [e.g. macOS, iOS, Windows]\n- Browser: [e.g. Chrome, Safari]\n- Version: [e.g. v1.0.0]\n\n## Additional Information\n\nAny other information about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: \"\\U0001F4A1 Feature Request\"\nabout: Suggest an idea for this project\ntitle: \"\"\nlabels: \"\"\nassignees: \"\"\n---\n\n# Feature Request\n\n## Describe the Feature\n\nA clear and concise description of what you want and what your use case is.\n\n## Describe the Solution You'd Like\n\nA clear and concise description of what you want to happen.\n\n## Describe Alternatives You've Considered\n\nA clear and concise description of any alternative solutions or features you've considered.\n\n## Additional Information\n\nAny other information about the feature here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "content": "---\nname: \"\\U0001F914 Questions and Help\"\nabout: This issue tracker is not for questions. Please ask questions at https://stackoverflow.com/questions/tagged/react.\ntitle: \"\"\nlabels: \"\"\nassignees: \"\"\n---\n\nGitHub Issues are reserved for Bug reports and Feature requests. Support requests that are created as issues are likely to be closed. We want to make sure you are able to find the help you seek. Please take a look at the following resources.\n\n## Coding Questions\n\nIf you have a coding question related to React, it might be better suited for Stack Overflow. It's a great place to browse through frequent questions about using React, as well as ask for help with specific questions.\n\nhttps://stackoverflow.com/questions/tagged/react\n\n## Support Forums\n\nThere are many online forums which are a great place for discussion about best practices and application architecture.\n\nhttps://reactjs.org/community/support.html#popular-discussion-forums\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\n  Thanks for your interest in the project. Bugs filed and PRs submitted are appreciated!\n\n  Before submitting a pull request, please make sure you're familiar with and follow the instructions in the contributing guidelines (found in the CONTRIBUTING.md file).\n\n  Also, please make sure you're familiar with and follow the instructions in the contributing guidelines (found in the CONTRIBUTING.md file).\n\n  If you're new to contributing to open source projects, you might find this free video course helpful: https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github\n\n  Please fill out the information below to expedite the review and (hopefully) merge of your pull request!\n-->\n\n## What\n\nWhat changes are being made? (e.g. feature, bug, docs, etc.)\n\n## Why\n\nWhy are these changes necessary?\n\n## How\n\nHow were these changes implemented?\n\n## Checklist\n\nHave you done all of these things?\n\n<!-- add \"N/A\" to the end of each line that's irrelevant to your changes -->\n<!-- to check an item, place an \"x\" in the box like so: \"- [x] Documentation\" -->\n\n- [ ] [Documentation](https://github.com/wellyshen/react-cool-form/tree/master/docs) added\n- [ ] Tests\n- [ ] TypeScript definitions updated\n- [ ] [Add a changeset](https://github.com/atlassian/changesets/blob/master/docs/adding-a-changeset.md)\n- [ ] Ready to be merged\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: npm\n    directory: \"/\"\n    schedule:\n      interval: daily\n      time: \"21:00\"\n    open-pull-requests-limit: 10\n    ignore:\n      - dependency-name: \"@changesets/changelog-github\"\n        versions:\n          - 0.3.0\n          - 0.4.0\n      - dependency-name: \"@rollup/plugin-commonjs\"\n        versions:\n          - 18.0.0\n      - dependency-name: husky\n        versions:\n          - 5.0.9\n          - 5.1.1\n          - 6.0.0\n      - dependency-name: rollup\n        versions:\n          - 2.40.0\n          - 2.42.4\n      - dependency-name: \"@testing-library/user-event\"\n        versions:\n          - 13.0.0\n          - 13.0.1\n          - 13.0.2\n          - 13.0.3\n          - 13.0.6\n          - 13.0.7\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\n  schedule:\n    #        ┌───────────── minute (0 - 59)\n    #        │  ┌───────────── hour (0 - 23)\n    #        │  │  ┌───────────── day of the month (1 - 31)\n    #        │  │  │ ┌───────────── month (1 - 12 or JAN-DEC)\n    #        │  │  │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)\n    #        │  │  │ │ │\n    #        │  │  │ │ │\n    #        │  │  │ │ │\n    #        *  *  * * *\n    - cron: \"40 18 * * 1\"\n\njobs:\n  CodeQL-Build:\n    # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest\n    runs-on: ubuntu-latest\n\n    permissions:\n      # required for all workflows\n      security-events: write\n\n      # only required for workflows in private repositories\n      actions: read\n      contents: read\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v3\n\n      # Initializes the CodeQL tools for scanning.\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v2\n        # Override language selection by uncommenting this and choosing your languages\n        with:\n          languages: javascript\n\n      # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).\n      # If this step fails, then you should remove it and run the build manually (see below).\n      - name: Autobuild\n        uses: github/codeql-action/autobuild@v2\n\n      # ℹ️ Command-line programs to run using the OS shell.\n      # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun\n\n      # ✏️ If the Autobuild fails above, remove it and uncomment the following\n      #    three lines and modify them (or add more) to build your code if your\n      #    project uses a compiled language\n\n      #- run: |\n      #     make bootstrap\n      #     make release\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v2\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  release:\n    name: Release\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v3\n\n      - name: Setup Node.js 16\n        uses: actions/setup-node@v3\n        with:\n          node-version: 16\n\n      - name: Install Dependencies\n        run: yarn\n\n      - name: Create Release Pull Request or Publish to npm\n        id: changesets\n        uses: changesets/action@v1\n        with:\n          # This expects you to have a script called release which does a build for your packages and calls changeset publish\n          publish: yarn release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/size.yml",
    "content": "name: Compressed Size\n\non: [pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v3\n      - uses: preactjs/compressed-size-action@v2\n        with:\n          repo-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          build-script: \"build:prod\"\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Lint / Test / Size\n\non:\n  push:\n    branches:\n      - master\n    tags-ignore:\n      - \"**\"\n  pull_request:\n    branches:\n      - master\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node: [16]\n\n    steps:\n      - uses: actions/checkout@v3\n      - name: Use Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v3\n        with:\n          node-version: ${{ matrix.node-version }}\n\n      - name: Get yarn cache directory path\n        id: yarn-cache-dir-path\n        run: echo \"::set-output name=dir::$(yarn cache dir)\"\n      - uses: actions/cache@v3\n        id: yarn-cache\n        with:\n          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}\n          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}\n          restore-keys: |\n            ${{ runner.os }}-yarn-\n\n      - name: Install dependencies\n        run: yarn install --frozen-lockfile\n      - name: Run lint\n        run: yarn lint\n      - name: Run test\n        run: yarn test:cov\n      - name: Run size limit\n        run: yarn size\n\n      - name: Coveralls GitHub Action\n        uses: coverallsapp/github-action@master\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# dependencies\nnode_modules\n\n# testing\ncoverage\n\n# production\ndist\n\n# misc\n.size-snapshot.json\n.DS_Store\n*.log"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nyarn lint-staged\n"
  },
  {
    "path": ".husky/pre-push",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nyarn test\nyarn size\n"
  },
  {
    "path": ".nvmrc",
    "content": "lts/*\n"
  },
  {
    "path": ".prettierignore",
    "content": "dist\ncoverage\napp\nexamples\nwebsite\n\n*.log\n.size-snapshot.json"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"type\": \"chrome\",\n      \"request\": \"launch\",\n      \"name\": \"Launch Chrome against localhost\",\n      \"url\": \"http://localhost:3000\",\n      \"webRoot\": \"${workspaceFolder}\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"typescript.tsdk\": \"node_modules/typescript/lib\"\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# react-cool-form\n\n## 0.4.1\n\n### Patch Changes\n\n- [#697](https://github.com/wellyshen/react-cool-form/pull/697) [`87eb83e`](https://github.com/wellyshen/react-cool-form/commit/87eb83e32aa11c0ddc6d87e3b5ba1e53886ed622) Thanks [@wellyshen](https://github.com/wellyshen)! - fix: `reset` method not working\n\n## 0.4.0\n\n### Minor Changes\n\n- [#654](https://github.com/wellyshen/react-cool-form/pull/654) [`291199a`](https://github.com/wellyshen/react-cool-form/commit/291199a021e6ae81af5bb5b79b77ac1f27f8b511) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): add `shouldFocus` option for `runValidation` method\n\n## 0.3.1\n\n### Patch Changes\n\n- [#640](https://github.com/wellyshen/react-cool-form/pull/640) [`61e1d53`](https://github.com/wellyshen/react-cool-form/commit/61e1d533e3d51fff33cbd91997adf280167fb7fc) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(types): use `RefObject` as the type of `form` method\n\n## 0.3.0\n\n### Minor Changes\n\n- [#633](https://github.com/wellyshen/react-cool-form/pull/633) [`bcb718a`](https://github.com/wellyshen/react-cool-form/commit/bcb718add9b21c49e6832b037e0e913d9c096c6c) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): turn the `shouldValidate` parameter of `setTouched` to object for the purpose of API consistency\n\n## 0.2.2\n\n### Patch Changes\n\n- [#619](https://github.com/wellyshen/react-cool-form/pull/619) [`8807efd`](https://github.com/wellyshen/react-cool-form/commit/8807efd0a3fea05e870c10a4ea22546f5f85a1fc) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(types): export more types\n\n## 0.2.1\n\n### Patch Changes\n\n- [#615](https://github.com/wellyshen/react-cool-form/pull/615) [`712bb21`](https://github.com/wellyshen/react-cool-form/commit/712bb21736bdc5990c38e1f822812f2b20081bea) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(types): use overloads for the type of `useFormState` and the `field` method of `useForm`\n\n## 0.2.0\n\n### Minor Changes\n\n- [#610](https://github.com/wellyshen/react-cool-form/pull/610) [`072da4b`](https://github.com/wellyshen/react-cool-form/commit/072da4b842d741e022ba2125528095e624c0f3d4) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): rename `mon` to `use`\n\n## 0.0.171\n\n### Patch Changes\n\n- [#572](https://github.com/wellyshen/react-cool-form/pull/572) [`2401051`](https://github.com/wellyshen/react-cool-form/commit/2401051c8128ffd8a17468bd8ec1f9ed0bf5b281) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(form-state): reset `isSubmitted` state when the user attempts to submnit the form\n\n## 0.0.170\n\n### Patch Changes\n\n- [#570](https://github.com/wellyshen/react-cool-form/pull/570) [`21bac87`](https://github.com/wellyshen/react-cool-form/commit/21bac870b3063a6f6c8ee976d07a6b07e2192bd9) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): rename `debug` event to `onStateChange`\n\n## 0.0.169\n\n### Patch Changes\n\n- [#568](https://github.com/wellyshen/react-cool-form/pull/568) [`d6bcac6`](https://github.com/wellyshen/react-cool-form/commit/d6bcac62266057f71bac0ceedaf731f3a62aea70) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): new `removeOnUnmounted` option\n\n## 0.0.168\n\n### Patch Changes\n\n- [`35516ad`](https://github.com/wellyshen/react-cool-form/commit/35516ad867efb6d1314a2580af360f9143423775) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFieldArray): reset values not working for conditional fields\n\n* [`c865f58`](https://github.com/wellyshen/react-cool-form/commit/c865f58504e416ccd55b4b2022f3092c1c841c80) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor: remove \"missing field name\" warnings\n\n## 0.0.167\n\n### Patch Changes\n\n- [#565](https://github.com/wellyshen/react-cool-form/pull/565) [`f1796dd`](https://github.com/wellyshen/react-cool-form/commit/f1796dd459f641544f0365ff6e4d331f8d5c45d7) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): reset form will cause `undefined` form values\n\n## 0.0.166\n\n### Patch Changes\n\n- [#562](https://github.com/wellyshen/react-cool-form/pull/562) [`310cecf`](https://github.com/wellyshen/react-cool-form/commit/310cecf66a658c615f38e3b243c0491321189ffc) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): automatically remove array fields getting wrong form values\n\n## 0.0.164\n\n### Patch Changes\n\n- [#555](https://github.com/wellyshen/react-cool-form/pull/555) [`546645a`](https://github.com/wellyshen/react-cool-form/commit/546645a9945092582237e47c28040e54716a7821) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useControlled): value not updated when working with conditional fields and setting default value from `defaultValue` option\n\n* [#553](https://github.com/wellyshen/react-cool-form/pull/553) [`6b33570`](https://github.com/wellyshen/react-cool-form/commit/6b33570e999ccd8e445aa227dbea386f3e3ec0d8) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useControlled): sync field value with its default value for a conditional field\n\n- [#556](https://github.com/wellyshen/react-cool-form/pull/556) [`b3edba8`](https://github.com/wellyshen/react-cool-form/commit/b3edba847372e8a7baf556bf78c71c1d25eba738) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useControlled): do not update default value when working with field-array\n\n## 0.0.163\n\n### Patch Changes\n\n- [#551](https://github.com/wellyshen/react-cool-form/pull/551) [`e285de3`](https://github.com/wellyshen/react-cool-form/commit/e285de3f1e3d96cda611d4cd0b6992ae49c74dcb) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor: reduce bundle size\n\n## 0.0.162\n\n### Patch Changes\n\n- [#549](https://github.com/wellyshen/react-cool-form/pull/549) [`b1cfeae`](https://github.com/wellyshen/react-cool-form/commit/b1cfeaea9d43d037d467789ff9c9db45e8cd6724) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): new `removeField` API\n\n## 0.0.161\n\n### Patch Changes\n\n- [#542](https://github.com/wellyshen/react-cool-form/pull/542) [`2e008df`](https://github.com/wellyshen/react-cool-form/commit/2e008dfc3cd933249eebe3d1c9e8f5203383e3e6) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor: reduce bundle size\n\n## 0.0.160\n\n### Patch Changes\n\n- [`2a18eca`](https://github.com/wellyshen/react-cool-form/commit/2a18eca80cf9ed0ec6c2cd9d6c479c0ea1c52449) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): reduce re-rendering times when a field un-mounted\n\n* [`088842d`](https://github.com/wellyshen/react-cool-form/commit/088842d2d825893b3246d9d381ef2b7b7071a04c) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFormState): unsubscribe the hook when the component is unmounted\n\n- [`3fb100e`](https://github.com/wellyshen/react-cool-form/commit/3fb100e263cae996acc28e87d611434f5a862836) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): `mon(\"submitCount\")` not triggering re-rendering\n\n## 0.0.159\n\n### Patch Changes\n\n- [`f457e82`](https://github.com/wellyshen/react-cool-form/commit/f457e829256e85400212fddf3d3697cfbd3541f8) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useControlled): form-level default value might not working with conditional fields\n\n* [`b3ec2f7`](https://github.com/wellyshen/react-cool-form/commit/b3ec2f7c105b53922ded53d84deffd8d0eaf012b) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): reduce bundle size\n\n- [`b31f0a2`](https://github.com/wellyshen/react-cool-form/commit/b31f0a2a3b18f0cd8c51e761379a62f02935e464) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): should remove form-level default value for conditional fields\n\n* [`b2d04e8`](https://github.com/wellyshen/react-cool-form/commit/b2d04e89197d0b38b255f06b9274a90025239014) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): when multiple `mon` method are using, only the latest one can work\n\n## 0.0.158\n\n### Patch Changes\n\n- [#536](https://github.com/wellyshen/react-cool-form/pull/536) [`ed0a7a6`](https://github.com/wellyshen/react-cool-form/commit/ed0a7a62cb9437a29e05012f1806a74f0f3f3e63) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): when dynamically hidding a field `getState` method will get default value\n\n## 0.0.157\n\n### Patch Changes\n\n- [#535](https://github.com/wellyshen/react-cool-form/pull/535) [`7491432`](https://github.com/wellyshen/react-cool-form/commit/749143284089fe956efbaab9de2d3869dabd4430) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): deprecate the `shouldFocus` parameter of `runValidation` API\n\n* [`341aa21`](https://github.com/wellyshen/react-cool-form/commit/341aa214d02dd7de8834827b4c3158d7e1acefb8) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor: refine the warning of getting `values` only\n\n- [`9dc4993`](https://github.com/wellyshen/react-cool-form/commit/9dc4993824083c9086927281135fb9265fd3936e) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useFormState): code refactor for smaller bundle size\n\n## 0.0.156\n\n### Patch Changes\n\n- [#530](https://github.com/wellyshen/react-cool-form/pull/530) [`62762d0`](https://github.com/wellyshen/react-cool-form/commit/62762d09701265ac5e8c68ffaade17dd37295e63) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFormState): `errorWithTouched` option not works in some cases\n\n* [#529](https://github.com/wellyshen/react-cool-form/pull/529) [`dc35110`](https://github.com/wellyshen/react-cool-form/commit/dc35110c7f93aa09d3d7cbaf672282a29c21699f) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): add `shouldFocus` for `runValidation` API\n\n- [#532](https://github.com/wellyshen/react-cool-form/pull/532) [`4c6fe9e`](https://github.com/wellyshen/react-cool-form/commit/4c6fe9ece87304ab2baa0db627176e7060f9e685) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): do not warn missing name when excluding a field via data attribute\n\n## 0.0.155\n\n### Patch Changes\n\n- [#527](https://github.com/wellyshen/react-cool-form/pull/527) [`10af065`](https://github.com/wellyshen/react-cool-form/commit/10af065a4ce4de597fbce2a5f68923f68c330021) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): delay = 0 is acceptable by `focus` method\n\n## 0.0.154\n\n### Patch Changes\n\n- [#519](https://github.com/wellyshen/react-cool-form/pull/519) [`5539448`](https://github.com/wellyshen/react-cool-form/commit/5539448c8c7ee1fedd19d12cb79d909fcf781fa4) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): new `setFocus` API\n\n* [`06e66f3`](https://github.com/wellyshen/react-cool-form/commit/06e66f38de31ebf335dd04543a5a118e1202d18a) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): when working with nested fields, built-in validation results are overrided\n\n## 0.0.153\n\n### Patch Changes\n\n- [`7de1f62`](https://github.com/wellyshen/react-cool-form/commit/7de1f62fb3b03d1aef8a5fe7041fedf1a48931fe) Thanks [@wellyshen](https://github.com/wellyshen)! - Docs(readme): add arrays-and-lists feature\n\n* [#518](https://github.com/wellyshen/react-cool-form/pull/518) [`cf7980f`](https://github.com/wellyshen/react-cool-form/commit/cf7980f72790bc6f5a95192fff629ec909ab38ad) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): when running field validation with nested field(s), error results will be overrided by the last field\n\n- [`c2459ee`](https://github.com/wellyshen/react-cool-form/commit/c2459eebbd18fd2cdbf58aa3552d51cbc650c5c0) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(types): rename `Map` to `ObjMap`\n\n## 0.0.152\n\n### Patch Changes\n\n- [`642650c`](https://github.com/wellyshen/react-cool-form/commit/642650c610893f65a83cd384a06bff1d82b5f4ba) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFieldArray): avoid touched and dirty values are set at negative index when using `push` method\n\n## 0.0.151\n\n### Patch Changes\n\n- [`d914de6`](https://github.com/wellyshen/react-cool-form/commit/d914de63a527a5188afd0ba0ea7203dcd9fd17cb) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFieldArray): field value not displayed when setting default value via `useFieldArray` hook\n\n## 0.0.150\n\n### Patch Changes\n\n- [`98cd462`](https://github.com/wellyshen/react-cool-form/commit/98cd46202296b720dff48352fd90d418596599b4) Thanks [@wellyshen](https://github.com/wellyshen)! - Docs(readme): update features section\n\n* [`cd8755b`](https://github.com/wellyshen/react-cool-form/commit/cd8755b265b6ec592312cb2690f18650ee1919de) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFieldArray): correct form ID warning message\n\n## 0.0.149\n\n### Patch Changes\n\n- [`bfab667`](https://github.com/wellyshen/react-cool-form/commit/bfab667e915f33ceb974195bf7cc12e10cde4be1) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat: new on form-state change event mode for `useFormState` hook\n\n## 0.0.148\n\n### Patch Changes\n\n- [#499](https://github.com/wellyshen/react-cool-form/pull/499) [`38cfd17`](https://github.com/wellyshen/react-cool-form/commit/38cfd17cd6b79345652a88ede0329ec328674139) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useFieldArray): provide simpler API\n\n## 0.0.147\n\n### Patch Changes\n\n- [#494](https://github.com/wellyshen/react-cool-form/pull/494) [`40e9b76`](https://github.com/wellyshen/react-cool-form/commit/40e9b76e74b2740fd8e6c309353bf9e77127998e) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat: shortcut for getting form's values\n\n* [#492](https://github.com/wellyshen/react-cool-form/pull/492) [`4f0dbaf`](https://github.com/wellyshen/react-cool-form/commit/4f0dbaf6610bad9977b474b92e158c0d83227755) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): throw multiple warning when getting form values with `mon` method\n\n## 0.0.146\n\n### Patch Changes\n\n- [`68b340a`](https://github.com/wellyshen/react-cool-form/commit/68b340a93188b23fd22303e7c097770be7b0cc56) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFieldArray): correct the type of return values\n\n## 0.0.145\n\n### Patch Changes\n\n- [#489](https://github.com/wellyshen/react-cool-form/pull/489) [`1eee601`](https://github.com/wellyshen/react-cool-form/commit/1eee601ef0b121387e1744290b0c62d62c0c277d) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFieldArray): fields not updated by helper methods\n\n## 0.0.144\n\n### Patch Changes\n\n- [#487](https://github.com/wellyshen/react-cool-form/pull/487) [`2d70034`](https://github.com/wellyshen/react-cool-form/commit/2d70034f2d4b8c9b4dd11a55eac42e1e19b3e41b) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useFieldArray): better API for fixing the side-effect of React keys and lists\n\n## 0.0.143\n\n### Patch Changes\n\n- [`4f9ae54`](https://github.com/wellyshen/react-cool-form/commit/4f9ae542010d413b1bc466a99b7c479249e39b2e) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFieldArray): reset fields not working properly\n\n* [`c5a700f`](https://github.com/wellyshen/react-cool-form/commit/c5a700f26004f5c7ec5772eb7578bfd6cff5cee4) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): reserve the default value of field-array from `removeField` method\n\n## 0.0.142\n\n### Patch Changes\n\n- [#481](https://github.com/wellyshen/react-cool-form/pull/481) [`90afddc`](https://github.com/wellyshen/react-cool-form/commit/90afddc7f61d76a891c0451410e383f8906f3c08) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFieldArray): reset not working\n\n* [#484](https://github.com/wellyshen/react-cool-form/pull/484) [`d5d68bc`](https://github.com/wellyshen/react-cool-form/commit/d5d68bcf7500caefc2faa3081bbdb46a6e9242be) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useControlled): controlled components not working with field-array\n\n## 0.0.140\n\n### Patch Changes\n\n- [#474](https://github.com/wellyshen/react-cool-form/pull/474) [`b6f7589`](https://github.com/wellyshen/react-cool-form/commit/b6f758990a59969c947158727a82789087f2566c) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): rename `select` method to `watch` for better understanding\n\n* [#474](https://github.com/wellyshen/react-cool-form/pull/474) [`3cdcd1b`](https://github.com/wellyshen/react-cool-form/commit/3cdcd1bd3a6c2bcdaab69846ac60f9c02ef597cf) Thanks [@wellyshen](https://github.com/wellyshen)! - Change `select` method to `mon` (a.k.a monitor)\n\n- [`2d0ba41`](https://github.com/wellyshen/react-cool-form/commit/2d0ba41c00036ed1526c8d92cff7dcd25cbfd0d7) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): wrong form values due to automatically remove a field\n\n## 0.0.139\n\n### Patch Changes\n\n- [`9bb9992`](https://github.com/wellyshen/react-cool-form/commit/9bb9992c666d52c17ce929d7d273b2fd885766b3) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor: refine warning messages\n\n## 0.0.138\n\n### Patch Changes\n\n- [`889e331`](https://github.com/wellyshen/react-cool-form/commit/889e3319d5f064607cef4dec42a3e5fb32cdadb4) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(utils): the side-effect of `cloneObject`\n\n## 0.0.137\n\n### Patch Changes\n\n- [`d808960`](https://github.com/wellyshen/react-cool-form/commit/d80896022c8322dfe4aed5facc57b40874151a82) [#466](https://github.com/wellyshen/react-cool-form/pull/466) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): `isDirty` not working with array type form values\n\n## 0.0.136\n\n### Patch Changes\n\n- [`c066ecc`](https://github.com/wellyshen/react-cool-form/commit/c066ecc5004d6b29d9d649a41f99290d5f52234f) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor: reduce bundle size\n\n## 0.0.135\n\n### Patch Changes\n\n- [`c4724a0`](https://github.com/wellyshen/react-cool-form/commit/c4724a04a1d60c767f501bc74f35393e835c31d1) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): skip unnecessary set state logic for `reset` method\n\n* [`573ab7b`](https://github.com/wellyshen/react-cool-form/commit/573ab7b6f29d2a7e9b503bd1cdaf772d903b5952) [#461](https://github.com/wellyshen/react-cool-form/pull/461) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): keep the value of a conditional field when `shouldRemoveField` option set to `false`'\n\n- [`ae11590`](https://github.com/wellyshen/react-cool-form/commit/ae115903890ee8d1b8f8d79d4acb399a375244c6) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor: refine missing \"name\" warnings\n\n## 0.0.134\n\n### Patch Changes\n\n- [`742ac71`](https://github.com/wellyshen/react-cool-form/commit/742ac71d7f2126745c10c044427bd31e2edb5cf0) [#451](https://github.com/wellyshen/react-cool-form/pull/451) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): conditional `checkbox`, `radio`, and `select` not working properly\n\n* [`cdf5808`](https://github.com/wellyshen/react-cool-form/commit/cdf580863bb0b9a096b7f6838040f7dd57f9eb37) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(utils): clear the redundant `empty` or `undefined` element(s) of an array\n\n## 0.0.133\n\n### Patch Changes\n\n- [`6dc3cca`](https://github.com/wellyshen/react-cool-form/commit/6dc3ccaaae66b11e5069084610143f760a387fc1) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): clear the `empty` element from the array type of form values\n\n## 0.0.132\n\n### Patch Changes\n\n- [`91cfe37`](https://github.com/wellyshen/react-cool-form/commit/91cfe37e794a1a6f1d4129c995598964173d39a9) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix: empty array values for `useForm` hook and `set` utility function\n\n* [`ada163b`](https://github.com/wellyshen/react-cool-form/commit/ada163b04922341575a9b979530f31006bfb9203) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(types): enhance the readability of type\n\n- [`d723cf0`](https://github.com/wellyshen/react-cool-form/commit/d723cf058cfab68a0c694b84553422617d2cafab) [#447](https://github.com/wellyshen/react-cool-form/pull/447) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(unset): remove the ancestry path of the unset property if needed\n\n## 0.0.131\n\n### Patch Changes\n\n- [`0e14ea7`](https://github.com/wellyshen/react-cool-form/commit/0e14ea76ea61e7025cc76b84b37c64b9b70d7fdd) [#444](https://github.com/wellyshen/react-cool-form/pull/444) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat: when only on form hook is using, the form id is not required anymore\n\n## 0.0.130\n\n### Patch Changes\n\n- [`723dceb`](https://github.com/wellyshen/react-cool-form/commit/723dcebb8f08fd3393ddcaa06ebf317c700ff337) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useControlled): use React.FocusEventHandler for the return props\n\n## 0.0.129\n\n### Patch Changes\n\n- [`8ae1f76`](https://github.com/wellyshen/react-cool-form/commit/8ae1f76a065a94375e2bf0143f8adcd981a63230) [#436](https://github.com/wellyshen/react-cool-form/pull/436) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): single checkbox input with valid `value` attribute, the value will be a string array\n\n## 0.0.128\n\n### Patch Changes\n\n- [`b3554f2`](https://github.com/wellyshen/react-cool-form/commit/b3554f28ed13e4d89ac437e42d4c370b1431ec09) [#433](https://github.com/wellyshen/react-cool-form/pull/433) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): add `id` and `class` for the `excludeFields` option\n\n## 0.0.126\n\n### Patch Changes\n\n- [`fe7942d`](https://github.com/wellyshen/react-cool-form/commit/fe7942d36ee2410ad3be9dc74318836b850cb6cb) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): fix potential side-effect of the values of form state\n\n## 0.0.125\n\n### Patch Changes\n\n- [`eb767bd`](https://github.com/wellyshen/react-cool-form/commit/eb767bd4758ebbec37efde3975c1eab822d2de6b) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): fix set default values side-effect\n\n## 0.0.124\n\n### Patch Changes\n\n- [`ed388fb`](https://github.com/wellyshen/react-cool-form/commit/ed388fbd2691b91e1335e88bd5238bac36f3a76c) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useFormState): use error instead warn for form id related exceptions\n\n## 0.0.123\n\n### Patch Changes\n\n- [`e7795c3`](https://github.com/wellyshen/react-cool-form/commit/e7795c30c36b26e402d4b07e458ee2f5f2617063) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useFormState): correct the URL of warnings\n\n## 0.0.122\n\n### Patch Changes\n\n- [`3f92f38`](https://github.com/wellyshen/react-cool-form/commit/3f92f3861baa7bfe51e1ba67525055c0ae97f09d) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat: new `useFormState` hook\n\n## 0.0.121\n\n### Patch Changes\n\n- [`cc3eb6c`](https://github.com/wellyshen/react-cool-form/commit/cc3eb6c845ba540de38bc2cab9a708b5bbc6739f) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): add `false` type for form validator\n\n## 0.0.120\n\n### Patch Changes\n\n- [`090f275`](https://github.com/wellyshen/react-cool-form/commit/090f27576174431f948c9a72ff3b8950b93d986c) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): do not unset subscribed state for conditional component\n\n## 0.0.119\n\n### Patch Changes\n\n- [`d4c7258`](https://github.com/wellyshen/react-cool-form/commit/d4c7258382b2aa5e4f2937973e7c5f253caf5a73) [#405](https://github.com/wellyshen/react-cool-form/pull/405) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): should call `debug` on every state changed\n\n* [`b0a5141`](https://github.com/wellyshen/react-cool-form/commit/b0a5141d589d1e82924e5f8b7eb4e8bee02bfbd6) [#403](https://github.com/wellyshen/react-cool-form/pull/403) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): do not trigger re-renders on reset if no any selected state\n\n## 0.0.118\n\n### Patch Changes\n\n- [`1d4e794`](https://github.com/wellyshen/react-cool-form/commit/1d4e79401f92ee2f4060efdfa377d769b6ff9a86) [#397](https://github.com/wellyshen/react-cool-form/pull/397) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): `dirty` and `isDirty` state not work correctly with reference type values\n\n## 0.0.117\n\n### Patch Changes\n\n- [`5797ca4`](https://github.com/wellyshen/react-cool-form/commit/5797ca447cb4024dd8f56e9b1e3afc6bef607b60) [#394](https://github.com/wellyshen/react-cool-form/pull/394) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): add \"select\" method\n\n## 0.0.116\n\n### Patch Changes\n\n- [`645b5f4`](https://github.com/wellyshen/react-cool-form/commit/645b5f4269737f535735e73eea242bb3a48dfff7) [#391](https://github.com/wellyshen/react-cool-form/pull/391) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor: refine types\n\n## 0.0.115\n\n### Patch Changes\n\n- [`38f64a8`](https://github.com/wellyshen/react-cool-form/commit/38f64a8423dd6b3bb8fe4b61e139312c74e9a113) [#384](https://github.com/wellyshen/react-cool-form/pull/384) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): prevent errors from calling `e.preventDefault()` and `e.stopPropagation()` when using `submit` or `reset` methods\n\n## 0.0.114\n\n### Patch Changes\n\n- [`87f7814`](https://github.com/wellyshen/react-cool-form/commit/87f7814bc6756254658938268d825533ae50c208) [#360](https://github.com/wellyshen/react-cool-form/pull/360) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useState): trigger `debug` callback whenever form state changed\n\n## 0.0.113\n\n### Patch Changes\n\n- [`a90c405`](https://github.com/wellyshen/react-cool-form/commit/a90c405a4a84b69855afa808afc1ef5d85252977) [#350](https://github.com/wellyshen/react-cool-form/pull/350) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): should warn for missing field name\n\n## 0.0.112\n\n### Patch Changes\n\n- [`841e904`](https://github.com/wellyshen/react-cool-form/commit/841e9043e3a387c48bdf617f6ea845dfa70b8f20) [#345](https://github.com/wellyshen/react-cool-form/pull/345) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): support non <form> element\n\n## 0.0.111\n\n### Patch Changes\n\n- [`1d6d0ae`](https://github.com/wellyshen/react-cool-form/commit/1d6d0aea93eff883cec506376bfbbd8e3cd941de) [#341](https://github.com/wellyshen/react-cool-form/pull/341) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): conditional form not working\n\n## 0.0.110\n\n### Patch Changes\n\n- [`26284c3`](https://github.com/wellyshen/react-cool-form/commit/26284c3007b3a64d5baa6eea0be3a792d0406e00) [#335](https://github.com/wellyshen/react-cool-form/pull/335) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): change `ignoreFields` to `excludeFields` & change `data-rcf-ignore` to `data-rcf-exclude`\n\n* [`34b1eb5`](https://github.com/wellyshen/react-cool-form/commit/34b1eb5fa602fac2b9e84cc7aabb550cae135c5f) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): exclude \"button\" type from form fields parser\n\n## 0.0.109\n\n### Patch Changes\n\n- [`facc86e`](https://github.com/wellyshen/react-cool-form/commit/facc86e086434aa158cd50e1ef1609254cbbb9d0) [#332](https://github.com/wellyshen/react-cool-form/pull/332) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): export `setDirty` method\n\n* [`649c03d`](https://github.com/wellyshen/react-cool-form/commit/649c03d8a5ccff33ac418414743e02493c350d67) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(utils): correct the logic of merging `object` with `array`\n\n- [`05cb324`](https://github.com/wellyshen/react-cool-form/commit/05cb324223e7fd9a2445253a93e2d491be96caee) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): code refactor for `setTouched`\n\n* [`68ccf7f`](https://github.com/wellyshen/react-cool-form/commit/68ccf7fd1ee7c91873986b824f19dace2b2b70fe) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(utils): exclude `Date` from `isPlainObject`\n\n## 0.0.108\n\n### Patch Changes\n\n- [`3d37b97`](https://github.com/wellyshen/react-cool-form/commit/3d37b9731d5e52e384806ffa8030ed2cbe6f4d93) [#329](https://github.com/wellyshen/react-cool-form/pull/329) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(utils): correct the logic of `unset`\n\n## 0.0.107\n\n### Patch Changes\n\n- [`64eccdb`](https://github.com/wellyshen/react-cool-form/commit/64eccdbe358d96e932cec6a74e45ad03e31af7a5) Thanks [@wellyshen](https://github.com/wellyshen)! - Docs(readme): add demo gif\n\n* [`db18bfa`](https://github.com/wellyshen/react-cool-form/commit/db18bfa3823c488905395b7da680e717842db4ad) [#328](https://github.com/wellyshen/react-cool-form/pull/328) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(utils): unset all types of value\n\n- [`a33fd6f`](https://github.com/wellyshen/react-cool-form/commit/a33fd6fc35f37b619fdb9f3f19ec1b4462112d96) Thanks [@wellyshen](https://github.com/wellyshen)! - Docs(readme): update demo gif\n\n* [`0f534a9`](https://github.com/wellyshen/react-cool-form/commit/0f534a90c2069c078e50fa0bac9b9a22e4d021c5) [#327](https://github.com/wellyshen/react-cool-form/pull/327) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(utils): handle `unset` exception\n\n## 0.0.106\n\n### Patch Changes\n\n- [`448f554`](https://github.com/wellyshen/react-cool-form/commit/448f554121214d779a8c99f3fc8e7741cb344769) [#321](https://github.com/wellyshen/react-cool-form/pull/321) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(utils): set array type value correctly\n\n* [`6755695`](https://github.com/wellyshen/react-cool-form/commit/67556955e92a222521014ccc0dd1b90610ad564b) [#322](https://github.com/wellyshen/react-cool-form/pull/322) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(utils): set object type value correctly\n\n- [`414c489`](https://github.com/wellyshen/react-cool-form/commit/414c4897e191f61824370244550604567483cd44) [#319](https://github.com/wellyshen/react-cool-form/pull/319) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(utils): remove `setTrueValues` utility function\n\n## 0.0.105\n\n### Patch Changes\n\n- [`02f25a3`](https://github.com/wellyshen/react-cool-form/commit/02f25a32f4fb1fd1136e52937f803b662ac8ea8a) [#312](https://github.com/wellyshen/react-cool-form/pull/312) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): require value for `setValue` and `setError`\n\n* [`d69188b`](https://github.com/wellyshen/react-cool-form/commit/d69188b3825197ee10bc240e816561e201af85b7) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): remove unnecessary logic\n\n- [`ad7336a`](https://github.com/wellyshen/react-cool-form/commit/ad7336abdc107e22c116873e43a4abe15d6aabca) [#311](https://github.com/wellyshen/react-cool-form/pull/311) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): rename the option of `getState` from `filterUntouchedError` to `errorWithTouched`\n\n## 0.0.104\n\n### Patch Changes\n\n- [`83c2474`](https://github.com/wellyshen/react-cool-form/commit/83c2474a4f3f7781774f8541084eed9953490034) [#303](https://github.com/wellyshen/react-cool-form/pull/303) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): remove `setValues` and `setErrors`\n\n* [`c623681`](https://github.com/wellyshen/react-cool-form/commit/c6236811fe4569f39be18a4c62c8a3860e5952cc) [#306](https://github.com/wellyshen/react-cool-form/pull/306) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): add `setTouched` method\n\n- [`0bec8fd`](https://github.com/wellyshen/react-cool-form/commit/0bec8fd7a097d3d5760053efd8b52273ec5140c7) [#307](https://github.com/wellyshen/react-cool-form/pull/307) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): add `clearErrors` method\n\n* [`817f762`](https://github.com/wellyshen/react-cool-form/commit/817f762aac28d075f4d30e0f34417b7a382c567f) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): rename `setFieldDirty` to `setDirty`\n\n- [`6936727`](https://github.com/wellyshen/react-cool-form/commit/69367272f03d9e347e786079d565f3f7ab3ec126) [#305](https://github.com/wellyshen/react-cool-form/pull/305) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): change `setFieldValue` to `setValue` & change `setFieldError` to `setError`\n\n* [`1c30b23`](https://github.com/wellyshen/react-cool-form/commit/1c30b23bc255d6d5c3cba9186757c8404e136d0f) [#308](https://github.com/wellyshen/react-cool-form/pull/308) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): combine `validateField` and `validateForm` into `runValidation`\n\n## 0.0.103\n\n### Patch Changes\n\n- [`d3c8247`](https://github.com/wellyshen/react-cool-form/commit/d3c824751eae453106ec1f0b0153a03730284744) [#301](https://github.com/wellyshen/react-cool-form/pull/301) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): pass all parameters back to the `onChange` handler of the `controller` API\n\n## 0.0.102\n\n### Patch Changes\n\n- [`e331cde`](https://github.com/wellyshen/react-cool-form/commit/e331cde6b28dc931e7cb72310264cd283687b375) [#299](https://github.com/wellyshen/react-cool-form/pull/299) Thanks [@wellyshen](https://github.com/wellyshen)! - Perf(useState): delete used state when a field is removed\n\n* [`8237117`](https://github.com/wellyshen/react-cool-form/commit/8237117868530731b247c8fd10e1cb66f1fe5f1e) Thanks [@wellyshen](https://github.com/wellyshen)! - Docs(readme): update to-do\n\n## 0.0.101\n\n### Patch Changes\n\n- [`9c1e7ce`](https://github.com/wellyshen/react-cool-form/commit/9c1e7ce72ba99bf7e3dc491034a346c1f35030c1) [#293](https://github.com/wellyshen/react-cool-form/pull/293) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(type): enhance types\n\n* [`569167b`](https://github.com/wellyshen/react-cool-form/commit/569167be2ffe61bacb5bf7c6d872db3b87f3d9f9) [#297](https://github.com/wellyshen/react-cool-form/pull/297) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(utils): `cloneObject` will not handle event object\n\n- [`e75aeb7`](https://github.com/wellyshen/react-cool-form/commit/e75aeb74c2a16b73fcbeb1e3486bf159776f5e5e) Thanks [@wellyshen](https://github.com/wellyshen)! - Docs(readme): update features\n\n* [`4399c18`](https://github.com/wellyshen/react-cool-form/commit/4399c1881f184af36cc163f22c12f014d668525b) [#296](https://github.com/wellyshen/react-cool-form/pull/296) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): rename `dirtyFields` state and option to `dirty`\n\n- [`0901fc3`](https://github.com/wellyshen/react-cool-form/commit/0901fc31482f8197b200c444fac18080946ef447) [#291](https://github.com/wellyshen/react-cool-form/pull/291) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): adjust the `parse` and `onChange` APIs of the `controller` method\n\n* [`5000470`](https://github.com/wellyshen/react-cool-form/commit/5000470f7ff57bf995cd121ee6c2614cb634ba11) [#295](https://github.com/wellyshen/react-cool-form/pull/295) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): rename the option of `setValues` from `touchedFields` to `touched`\n\n- [`e1cd135`](https://github.com/wellyshen/react-cool-form/commit/e1cd135ccc90fba025caf6bb49712c3afe5bc644) [#294](https://github.com/wellyshen/react-cool-form/pull/294) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): rename `removeUnmountedField` to `shouldRemoveField`\n\n## 0.0.100\n\n### Patch Changes\n\n- [`f537695`](https://github.com/wellyshen/react-cool-form/commit/f53769513b8e221a379008d7b2c86f9e441682e8) [#288](https://github.com/wellyshen/react-cool-form/pull/288) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): can not clear field(s) due to the side-effect of caching paths\n\n## 0.0.99\n\n### Patch Changes\n\n- [`ad0fa46`](https://github.com/wellyshen/react-cool-form/commit/ad0fa462f0febe511416dee1f14cc77a3652001f) [#287](https://github.com/wellyshen/react-cool-form/pull/287) Thanks [@wellyshen](https://github.com/wellyshen)! - Perf(utils): cache converted pathes\n\n## 0.0.98\n\n### Patch Changes\n\n- [`abd1f39`](https://github.com/wellyshen/react-cool-form/commit/abd1f3979c8501af2d46bc89acca0402aa6acf35) [#285](https://github.com/wellyshen/react-cool-form/pull/285) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): skip warning for field with `data-rcf-ignore`\n\n* [`baf7fcf`](https://github.com/wellyshen/react-cool-form/commit/baf7fcf7a2ac238673dea27cc0508cfcd598b47d) [#284](https://github.com/wellyshen/react-cool-form/pull/284) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): unset nested array value\n\n- [`6bf0e46`](https://github.com/wellyshen/react-cool-form/commit/6bf0e46a7e19d9858a6ebd2788d40bfae08b88d3) [#283](https://github.com/wellyshen/react-cool-form/pull/283) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): do not count the `valid` key as error when use built-in validation with state mode\n\n## 0.0.97\n\n### Patch Changes\n\n- [`fdd269c`](https://github.com/wellyshen/react-cool-form/commit/fdd269ca3e4caf91aea54cac708d0d8ab6bb8088) [#279](https://github.com/wellyshen/react-cool-form/pull/279) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): correc the type of `setFieldValue`\n\n## 0.0.96\n\n### Patch Changes\n\n- [`b3e2257`](https://github.com/wellyshen/react-cool-form/commit/b3e2257b494d0a626680711fe45ab7e99a1e4eb8) [#278](https://github.com/wellyshen/react-cool-form/pull/278) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(types): change `Errors` to `FormErrors`\n\n* [`cf0dc60`](https://github.com/wellyshen/react-cool-form/commit/cf0dc605645be5755840e4aa268a020b1394ff4a) [#276](https://github.com/wellyshen/react-cool-form/pull/276) Thanks [@wellyshen](https://github.com/wellyshen)! - Perf(useForm): avoid unnecessary re-renders when getting empty state\n\n- [`1600d0a`](https://github.com/wellyshen/react-cool-form/commit/1600d0acbaef9877654dc481022c5bae1bd26448) [#277](https://github.com/wellyshen/react-cool-form/pull/277) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): handle `getState` exception\n\n* [`cf4b645`](https://github.com/wellyshen/react-cool-form/commit/cf4b6451c63ec8dfb8275dec5759701829b8aed2) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(types): re-order types\n\n## 0.0.95\n\n### Patch Changes\n\n- [`3a24549`](https://github.com/wellyshen/react-cool-form/commit/3a245496a5b70c6e1bb77b9081d98aa24b056865) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): fix variable typo\n\n* [`531aa74`](https://github.com/wellyshen/react-cool-form/commit/531aa74d096771b0abb875a066d0bc5ef5394090) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): change milestone to to-do\n\n## 0.0.94\n\n### Patch Changes\n\n- [`e267f75`](https://github.com/wellyshen/react-cool-form/commit/e267f75437001c8959257613e2d0aa3e64cfaff3) [#272](https://github.com/wellyshen/react-cool-form/pull/272) Thanks [@wellyshen](https://github.com/wellyshen)! - Feat(useForm): change `config` from required to optional\n\n## 0.0.93\n\n### Patch Changes\n\n- [`89a0647`](https://github.com/wellyshen/react-cool-form/commit/89a06477b97c6ac9a66694c88cad0afdb45112a1) Thanks [@wellyshen](https://github.com/wellyshen)! - Docs(readme): update bundle size\n\n* [`a3b7228`](https://github.com/wellyshen/react-cool-form/commit/a3b7228e4693fad0df80b117aa8899850a959bc2) [#271](https://github.com/wellyshen/react-cool-form/pull/271) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(types): adjust .d.ts\n\n## 0.0.92\n\n### Patch Changes\n\n- [`cf8d06e`](https://github.com/wellyshen/react-cool-form/commit/cf8d06e4e10002fa75af15e2ec2bc406c3d128ad) [#269](https://github.com/wellyshen/react-cool-form/pull/269) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): default value attribute not working when reset form\n\n* [`46bad87`](https://github.com/wellyshen/react-cool-form/commit/46bad87c459c1fdbf86c31e19c556bc3e76a39fe) Thanks [@wellyshen](https://github.com/wellyshen)! - Refactor(useForm): narrow down warning link URL\n\n- [`f6a8ed5`](https://github.com/wellyshen/react-cool-form/commit/f6a8ed5a14e36c761bc7afd662b256bb987eb483) Thanks [@wellyshen](https://github.com/wellyshen)! - Docs: update links\n\n## 0.0.91\n\n### Patch Changes\n\n- [`028b95e`](https://github.com/wellyshen/react-cool-form/commit/028b95e77ff7d683c98a74423ae05efe0409265d) [#265](https://github.com/wellyshen/react-cool-form/pull/265) Thanks [@wellyshen](https://github.com/wellyshen)! - Perf(useForm): do not trigger re-rendering when imperatively setting the same values\n\n* [`f6b97a2`](https://github.com/wellyshen/react-cool-form/commit/f6b97a28f91946900fb2c8c0139367c48ef47d4d) [#266](https://github.com/wellyshen/react-cool-form/pull/266) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): update `defaultValues` by `reset(nextValues)`\n\n- [`2d25b4a`](https://github.com/wellyshen/react-cool-form/commit/2d25b4a4e0f27a5db2890b75c605aff883bc924f) [#267](https://github.com/wellyshen/react-cool-form/pull/267) Thanks [@wellyshen](https://github.com/wellyshen)! - Perf(useForm): do not trigger `isValidating` when running field-level validation\n\n## 0.0.90\n\n### Patch Changes\n\n- [`6c73fb0`](https://github.com/wellyshen/react-cool-form/commit/6c73fb046077120726ea84fb5743f6e96fa71e53) [#262](https://github.com/wellyshen/react-cool-form/pull/262) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): field updating laggy due to conditional fields\n\n* [`f8fe312`](https://github.com/wellyshen/react-cool-form/commit/f8fe31269b7846464f00475da938a3b809f2ce39) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): remove badge\n\n## 0.0.89\n\n### Patch Changes\n\n- [`74c6bd5`](https://github.com/wellyshen/react-cool-form/commit/74c6bd55a6fa80af24721d1d007cfe78181c7509) [#260](https://github.com/wellyshen/react-cool-form/pull/260) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): add `builtInValidationMode` option\n\n* [`42e3844`](https://github.com/wellyshen/react-cool-form/commit/42e384444732296194d9e165231976d06f835d72) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): remove warning\n\n## 0.0.88\n\n### Patch Changes\n\n- [`aa86eee`](https://github.com/wellyshen/react-cool-form/commit/aa86eee774325ed128828703dcb8d1ddc65dc36a) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): fix broken links\n\n## 0.0.87\n\n### Patch Changes\n\n- [`8af3145`](https://github.com/wellyshen/react-cool-form/commit/8af3145816707306ea2ec55a4ee0832b7e4a0693) [#255](https://github.com/wellyshen/react-cool-form/pull/255) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(types): export more types\n\n* [`c487230`](https://github.com/wellyshen/react-cool-form/commit/c48723020fa795b158e368be16dbd81f747fa822) [#253](https://github.com/wellyshen/react-cool-form/pull/253) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): add field-names callback for the option of `setValues`\n\n- [`8cde001`](https://github.com/wellyshen/react-cool-form/commit/8cde0013b486f8c9d10fd57da9c52b6a92b05934) [#256](https://github.com/wellyshen/react-cool-form/pull/256) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(types): enhance the readability of type\n\n## 0.0.86\n\n### Patch Changes\n\n- [`8588512`](https://github.com/wellyshen/react-cool-form/commit/8588512713ff7e3bbfc026f55aa07ebb6ae65f9a) [#250](https://github.com/wellyshen/react-cool-form/pull/250) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): use `formState` instead of the `getState` method for event handlers\n\n* [`c09d541`](https://github.com/wellyshen/react-cool-form/commit/c09d541f3caf6517d557f4f817c832b458d43ef8) [#252](https://github.com/wellyshen/react-cool-form/pull/252) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): consist event's options\n\n## 0.0.85\n\n### Patch Changes\n\n- [`8da0654`](https://github.com/wellyshen/react-cool-form/commit/8da065490fdd845646c6b4823e17f7fb07ab44d6) [#248](https://github.com/wellyshen/react-cool-form/pull/248) Thanks [@wellyshen](https://github.com/wellyshen)! - perf(useForm): performance optimizing\n\n## 0.0.84\n\n### Patch Changes\n\n- [`d87a6bf`](https://github.com/wellyshen/react-cool-form/commit/d87a6bf8d8265bb6b65a6eb4f5539a1cfb8f7930) [#247](https://github.com/wellyshen/react-cool-form/pull/247) Thanks [@wellyshen](https://github.com/wellyshen)! - perf(useForm): minimize the re-renders of `setValues`\n\n* [`099ac5c`](https://github.com/wellyshen/react-cool-form/commit/099ac5cea87d4946278163dbcd97d3670e4871b7) [#245](https://github.com/wellyshen/react-cool-form/pull/245) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): include non form input elements into the set all touched of `submit`\n\n## 0.0.82\n\n### Patch Changes\n\n- [`476890f`](https://github.com/wellyshen/react-cool-form/commit/476890f9e361a1ea165ee047df94bb1d48b27045) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(type): correct the type of `validateField`\n\n* [`8398e39`](https://github.com/wellyshen/react-cool-form/commit/8398e396c3b834f340bda706d746c7509759b5f1) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update example\n\n## 0.0.81\n\n### Patch Changes\n\n- [`5e02e6e`](https://github.com/wellyshen/react-cool-form/commit/5e02e6e4791c6577d0a2af03cda74828ee768b79) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update warning\n\n## 0.0.80\n\n### Patch Changes\n\n- [`649d336`](https://github.com/wellyshen/react-cool-form/commit/649d336b54ac7b00375aa6cbe024da53cea002c9) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): correct grammer\n\n## 0.0.79\n\n### Patch Changes\n\n- [`0125f87`](https://github.com/wellyshen/react-cool-form/commit/0125f87fd5187c67d066ebf6ca6f2f89b07eafd6) [#237](https://github.com/wellyshen/react-cool-form/pull/237) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): add `removeUnmountedField` config\n\n* [`02a759e`](https://github.com/wellyshen/react-cool-form/commit/02a759e8e785373ec45f27f10d62db7722d7859f) [#236](https://github.com/wellyshen/react-cool-form/pull/236) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): crash due to undefined field parsers\n\n- [`43bc612`](https://github.com/wellyshen/react-cool-form/commit/43bc6127bbdcc71fed1616c042eeddf50d2a1ddd) [#234](https://github.com/wellyshen/react-cool-form/pull/234) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): dynamic fields not working\n\n## 0.0.78\n\n### Patch Changes\n\n- [`167fcb6`](https://github.com/wellyshen/react-cool-form/commit/167fcb652bf6c2ee12fe140c2b3ea8cf548aebc8) [#232](https://github.com/wellyshen/react-cool-form/pull/232) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): change `getState`'s option name from `filterUntouchedErrors` to `filterUntouchedError`\n\n## 0.0.77\n\n### Patch Changes\n\n- [`9f40af2`](https://github.com/wellyshen/react-cool-form/commit/9f40af21806db37f1f4f6254459cb38f92e145ab) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update features and example\n\n* [`155a140`](https://github.com/wellyshen/react-cool-form/commit/155a14079079ad16ab5228fc606c9cac4764512e) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): add more information link for `getState`\n\n- [`d23eef5`](https://github.com/wellyshen/react-cool-form/commit/d23eef5550868e9cb580b6a0e2c0ea9355444bdf) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update the demo link of example\n\n## 0.0.76\n\n### Patch Changes\n\n- [`cedfe8a`](https://github.com/wellyshen/react-cool-form/commit/cedfe8a45dca7e426524f85d899ea4bfeefb6791) Thanks [@wellyshen](https://github.com/wellyshen)! - docs: update readme and document site\n\n## 0.0.75\n\n### Patch Changes\n\n- [`acc5b4e`](https://github.com/wellyshen/react-cool-form/commit/acc5b4e185bee53055292fbf22fb5deeb5b1081b) Thanks [@wellyshen](https://github.com/wellyshen)! - docs: add form-level validation\n\n## 0.0.74\n\n### Patch Changes\n\n- [`a2ccfd0`](https://github.com/wellyshen/react-cool-form/commit/a2ccfd07c9111c9764175b1a904763004f5bb007) Thanks [@wellyshen](https://github.com/wellyshen)! - docs: sync examples with demo apps\n\n## 0.0.72\n\n### Patch Changes\n\n- [`11a779e`](https://github.com/wellyshen/react-cool-form/commit/11a779e270c07a8e6eb19e76081d6d389f82d201) [#222](https://github.com/wellyshen/react-cool-form/pull/222) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): reduce unnecessary renders for `getState`\n\n## 0.0.71\n\n### Patch Changes\n\n- [`f702cc8`](https://github.com/wellyshen/react-cool-form/commit/f702cc8c25d0aa0c1dc7ac731add2fe80fe3e741) Thanks [@wellyshen](https://github.com/wellyshen)! - chore(package): change homepage URL\n\n## 0.0.70\n\n### Patch Changes\n\n- [`6dca6ab`](https://github.com/wellyshen/react-cool-form/commit/6dca6ab47b62533d097463c25a818102a4be7623) Thanks [@wellyshen](https://github.com/wellyshen)! - docs: update getting-started & the API url of README.md & add \"API Reference\" page\n\n## 0.0.69\n\n### Patch Changes\n\n- [`5b2347c`](https://github.com/wellyshen/react-cool-form/commit/5b2347c47d557252168dae54519c8f495b1b09cd) Thanks [@wellyshen](https://github.com/wellyshen)! - docs: update readme\n\n## 0.0.68\n\n### Patch Changes\n\n- [`0c6f761`](https://github.com/wellyshen/react-cool-form/commit/0c6f7618fdfd7e3d813faafb929e198b69e78349) Thanks [@wellyshen](https://github.com/wellyshen)! - docs: update example\n\n## 0.0.67\n\n### Patch Changes\n\n- [`d887fb9`](https://github.com/wellyshen/react-cool-form/commit/d887fb946177899b3a4bde1dc031eed570df53c0) [#210](https://github.com/wellyshen/react-cool-form/pull/210) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): add warning for getting `values` state alone\n\n## 0.0.66\n\n### Patch Changes\n\n- [`8487733`](https://github.com/wellyshen/react-cool-form/commit/84877333542a20e96763e7dec420b84a9ca8541d) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update codesandbox link\n\n## 0.0.65\n\n### Patch Changes\n\n- [`0649089`](https://github.com/wellyshen/react-cool-form/commit/064908920ada6ad411095a2af95844e47b6a4888) [#207](https://github.com/wellyshen/react-cool-form/pull/207) Thanks [@wellyshen](https://github.com/wellyshen)! - Fix(useForm): correct the `onChange` type of `controller`\n\n## 0.0.64\n\n### Patch Changes\n\n- [`b30e638`](https://github.com/wellyshen/react-cool-form/commit/b30e6381f210705573e95c02d8574352e342deda) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): correct grammar\n\n## 0.0.63\n\n### Patch Changes\n\n- [`bcc1e9b`](https://github.com/wellyshen/react-cool-form/commit/bcc1e9b75a9fe17e47bdf372b96894a6323efe34) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update features section\n\n## 0.0.62\n\n### Patch Changes\n\n- [`edcf47d`](https://github.com/wellyshen/react-cool-form/commit/edcf47d80bcb3c779cd2bd9f65f434553afd6724) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update example\n\n* [`d1199b6`](https://github.com/wellyshen/react-cool-form/commit/d1199b6b68d114655805eab94336ade91384c20a) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): add features section\n\n- [`e7b29d9`](https://github.com/wellyshen/react-cool-form/commit/e7b29d9c2aa7d0e9ecdba038ce5fea223e98e5f2) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update demo link\n\n## 0.0.61\n\n### Patch Changes\n\n- [`3caa0d1`](https://github.com/wellyshen/react-cool-form/commit/3caa0d1c92f481b1f3aa54b16a8e1245f64969a0) [#201](https://github.com/wellyshen/react-cool-form/pull/201) Thanks [@wellyshen](https://github.com/wellyshen)! - perf: use `dequal` instead of `fast-deep-equal`\n\n## 0.0.60\n\n### Patch Changes\n\n- [`577de2a`](https://github.com/wellyshen/react-cool-form/commit/577de2a3ff3726bbfd497f810b734f3be7b0c8fd) [#200](https://github.com/wellyshen/react-cool-form/pull/200) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): shorten code\n\n* [`b09a2c0`](https://github.com/wellyshen/react-cool-form/commit/b09a2c0b7e22bb21e49cb94c60e6819aed2b2156) [#199](https://github.com/wellyshen/react-cool-form/pull/199) Thanks [@wellyshen](https://github.com/wellyshen)! - add `parse` option for field ref & correct the behavior of `controller`\n\n- [`a089883`](https://github.com/wellyshen/react-cool-form/commit/a0898831fda1858ee44841518fbc1b96aa8d972f) [#197](https://github.com/wellyshen/react-cool-form/pull/197) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): support `valueAsNumber` and `valueAsDate` for field ref\n\n## 0.0.59\n\n### Patch Changes\n\n- [`e50b2ff`](https://github.com/wellyshen/react-cool-form/commit/e50b2ff3efa4b1051a79de1a2bc7374442374e22) [#195](https://github.com/wellyshen/react-cool-form/pull/195) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): change `formRef` to `form`\n\n* [`a0c41f8`](https://github.com/wellyshen/react-cool-form/commit/a0c41f833929c67b571513a4783e6b566097c8c3) [#195](https://github.com/wellyshen/react-cool-form/pull/195) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): change `validate` to `field`\n\n- [`b769633`](https://github.com/wellyshen/react-cool-form/commit/b76963398517ff5c98ebadfca12a0dad4e6093a8) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): remove form ref warning\n\n## 0.0.58\n\n### Patch Changes\n\n- [`df94182`](https://github.com/wellyshen/react-cool-form/commit/df94182b0c327053535fb7c69b99b8dd518e0173) [#189](https://github.com/wellyshen/react-cool-form/pull/189) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): use `valueAsNumber` instead `parseFloat()` for converting data\n\n* [`4eae04c`](https://github.com/wellyshen/react-cool-form/commit/4eae04c9feb6dde4d07b0c83633ce95792c96ea2) [#193](https://github.com/wellyshen/react-cool-form/pull/193) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): correct the logic of `controller` method\n\n- [`26936f5`](https://github.com/wellyshen/react-cool-form/commit/26936f5b8f8f49f39c115d5acb913a94fd0fdb50) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): rename `handleFieldChange` to `handleChangeEvent`\n\n## 0.0.57\n\n### Patch Changes\n\n- [`ae3447c`](https://github.com/wellyshen/react-cool-form/commit/ae3447cbefdcc025e9ca7f10858003d088db38f4) Thanks [@wellyshen](https://github.com/wellyshen)! - chore: update slogan\n\n## 0.0.56\n\n### Patch Changes\n\n- [`120bea9`](https://github.com/wellyshen/react-cool-form/commit/120bea976f9692c022d3c77abdd7201307ebc453) Thanks [@wellyshen](https://github.com/wellyshen)! - docs: update readme\n\n## 0.0.55\n\n### Patch Changes\n\n- [`e60deba`](https://github.com/wellyshen/react-cool-form/commit/e60deba4f44e273ff3225bb24579a27dd5f25237) [#181](https://github.com/wellyshen/react-cool-form/pull/181) Thanks [@wellyshen](https://github.com/wellyshen)! - feat: expose the `unset` utility function\n\n## 0.0.54\n\n### Patch Changes\n\n- [`53fd53c`](https://github.com/wellyshen/react-cool-form/commit/53fd53c489f58f70eac35d05d103c267edc30b69) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(utils): filter the `undefined` property only for `filterError`\n\n## 0.0.53\n\n### Patch Changes\n\n- [`573c7f7`](https://github.com/wellyshen/react-cool-form/commit/573c7f79c3c2e70d429e8759724b317aa5c28bd3) [#178](https://github.com/wellyshen/react-cool-form/pull/178) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useState): remove `setDefaultValuesRef` method\n\n## 0.0.52\n\n### Patch Changes\n\n- [`fa7ebf6`](https://github.com/wellyshen/react-cool-form/commit/fa7ebf6d56f145a82cb30f1e981fc6b3b00f9df6) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(utils): delete the filtered property for `filterError()`\n\n* [`68d232d`](https://github.com/wellyshen/react-cool-form/commit/68d232d66844389a7416700cfd8d485bf855a92e) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): refine the type of `controller`\n\n## 0.0.51\n\n### Patch Changes\n\n- [`a9bc203`](https://github.com/wellyshen/react-cool-form/commit/a9bc203a74919e3693ecc8dbd0d5e125c22bde9a) Thanks [@wellyshen](https://github.com/wellyshen)! - perf(utils): improve the performance of `getIsDirty()`\n\n* [`7e296d0`](https://github.com/wellyshen/react-cool-form/commit/7e296d02a248d636aa6718d7f79d42d3ad20bfa7) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update example\n\n- [`c4acafc`](https://github.com/wellyshen/react-cool-form/commit/c4acafcb96378b369321236eb767bd93ec25686b) Thanks [@wellyshen](https://github.com/wellyshen)! - chore: refine project structure\n\n* [`7eb1693`](https://github.com/wellyshen/react-cool-form/commit/7eb1693af7995207550da212435e4272ec15ff39) [#175](https://github.com/wellyshen/react-cool-form/pull/175) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): correct the behavior of built-in validation\n\n- [`57278de`](https://github.com/wellyshen/react-cool-form/commit/57278de50edbf5959f51472969b659c3743022e8) [#174](https://github.com/wellyshen/react-cool-form/pull/174) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): adjust the API of `getState()`\n\n* [`9af09b2`](https://github.com/wellyshen/react-cool-form/commit/9af09b2b01552414897b041deb6e1c64ca21ca9f) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update example\n\n- [`daac107`](https://github.com/wellyshen/react-cool-form/commit/daac107aafc61ccc761ad79f47fa9a4a441896aa) [#173](https://github.com/wellyshen/react-cool-form/pull/173) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): re-use methods\n\n## 0.0.50\n\n### Patch Changes\n\n- [`af56a0b`](https://github.com/wellyshen/react-cool-form/commit/af56a0b818f61fe971417fe7daf917d31d166f00) [#171](https://github.com/wellyshen/react-cool-form/pull/171) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): auto delete undefined value for `setFieldValue()`\n\n* [`f1e05d1`](https://github.com/wellyshen/react-cool-form/commit/f1e05d1ba9a1f142c2a1fddef7a80bca69ba05fb) [#169](https://github.com/wellyshen/react-cool-form/pull/169) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): correct the logic of `dirtyFields` and `isDirty`\n\n- [`e7adb99`](https://github.com/wellyshen/react-cool-form/commit/e7adb99ec60171bebdbbd2d648f7027e2209a459) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): prevent un-necessary default values checking\n\n## 0.0.49\n\n### Patch Changes\n\n- [`aef2df3`](https://github.com/wellyshen/react-cool-form/commit/aef2df3c714faa692d4d42eb91a5f6eac44fdf52) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): crash due to filer untouched errors\n\n## 0.0.48\n\n### Patch Changes\n\n- [`80879a3`](https://github.com/wellyshen/react-cool-form/commit/80879a3889d9a25a46f37e0f604408c71d6fcbf4) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update example\n\n## 0.0.47\n\n### Patch Changes\n\n- [`75f42bc`](https://github.com/wellyshen/react-cool-form/commit/75f42bcd15e512250b006a4058a28da7f0c17d78) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update the type definition section\n\n## 0.0.46\n\n### Patch Changes\n\n- [`988f9a8`](https://github.com/wellyshen/react-cool-form/commit/988f9a8df656e47921b763e01d122706e13d2a2a) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): add type definition\n\n* [`35f9872`](https://github.com/wellyshen/react-cool-form/commit/35f9872d1db152f045cdee6434b7de1a26a996be) [#164](https://github.com/wellyshen/react-cool-form/pull/164) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): adjust the `watch` arg of `getState()`\n\n## 0.0.45\n\n### Patch Changes\n\n- [`56345dc`](https://github.com/wellyshen/react-cool-form/commit/56345dcf46776b590b95833f9c11e6a36d6920ba) [#161](https://github.com/wellyshen/react-cool-form/pull/161) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(type): enhance the type of `controller`\n\n* [`996eb40`](https://github.com/wellyshen/react-cool-form/commit/996eb40d118c8febd0e75f36e34f3cb56ef7a19e) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor: move utility functions from useForm to utils\n\n- [`e69ea75`](https://github.com/wellyshen/react-cool-form/commit/e69ea75fabff4a9d32f31f14bce72398f29ab917) [#163](https://github.com/wellyshen/react-cool-form/pull/163) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): get touched error only\n\n## 0.0.44\n\n### Patch Changes\n\n- [`afab297`](https://github.com/wellyshen/react-cool-form/commit/afab2978d4344dc332635b1926c250b21ecaf5e4) [#159](https://github.com/wellyshen/react-cool-form/pull/159) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): add `format` option for `controller`\n\n* [`5c79904`](https://github.com/wellyshen/react-cool-form/commit/5c7990433e9df4a7972f882e5566ed17625f25a7) [#157](https://github.com/wellyshen/react-cool-form/pull/157) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): change the `parser` option of controller to `parse`\n\n## 0.0.43\n\n### Patch Changes\n\n- [`6a2939d`](https://github.com/wellyshen/react-cool-form/commit/6a2939deb842977eabd0495013c70f726bc6adb1) [#155](https://github.com/wellyshen/react-cool-form/pull/155) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): remove `iControlFields` and `excludeFields` configs use `ignoreFields` instead\n\n## 0.0.42\n\n### Patch Changes\n\n- [`0df48ee`](https://github.com/wellyshen/react-cool-form/commit/0df48ee12ac086a33e5b217034b07628a21b2f21) [#149](https://github.com/wellyshen/react-cool-form/pull/149) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): built-in errors not be cleaned\n\n## 0.0.41\n\n### Patch Changes\n\n- [`57f5fc9`](https://github.com/wellyshen/react-cool-form/commit/57f5fc904aa016a1c7d1c2a7157a7226ea163f62) [#148](https://github.com/wellyshen/react-cool-form/pull/148) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): avoid duplicated set field touched for controller\n\n* [`9a060e0`](https://github.com/wellyshen/react-cool-form/commit/9a060e0faff59c320c147c6bf396c6c51176f045) [#146](https://github.com/wellyshen/react-cool-form/pull/146) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): consist options name of the `setFieldValue` method\n\n## 0.0.40\n\n### Patch Changes\n\n- [`701b8f9`](https://github.com/wellyshen/react-cool-form/commit/701b8f95a2719dc07f59351a1ab4a042c2527708) [#144](https://github.com/wellyshen/react-cool-form/pull/144) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): turn isSubmitted to `true` once submit is successful\n\n## 0.0.39\n\n### Patch Changes\n\n- [`cf06541`](https://github.com/wellyshen/react-cool-form/commit/cf06541eb192f6bb66d0b9b4989f90406f219ce3) [#142](https://github.com/wellyshen/react-cool-form/pull/142) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): correct the logic between controlled and un-controlled fields\n\n* [`3e3ef26`](https://github.com/wellyshen/react-cool-form/commit/3e3ef26624289b8065ca59bb33b3cdf255f8f652) [#143](https://github.com/wellyshen/react-cool-form/pull/143) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): get the deep intial value as the default value of field\n\n- [`7399a99`](https://github.com/wellyshen/react-cool-form/commit/7399a9920eaf3938a513ba67f4978d97b47c4f87) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor: use default value for events\n\n* [`8c8209d`](https://github.com/wellyshen/react-cool-form/commit/8c8209de9abd1234bca8458d655ad537232ba30f) [#141](https://github.com/wellyshen/react-cool-form/pull/141) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): use validate field instead of validate form for single updated field\n\n- [`401f7ec`](https://github.com/wellyshen/react-cool-form/commit/401f7ec539527d7a28c63ada663b9dba28ca7658) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): remove the logic of checking exist errors on submit\n\n* [`1d3c5e8`](https://github.com/wellyshen/react-cool-form/commit/1d3c5e8618f5f5eb72c95c1e99838fff33d0893d) [#139](https://github.com/wellyshen/react-cool-form/pull/139) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useState): debug event not be sent correctly\n\n## 0.0.38\n\n### Patch Changes\n\n- [`d6d254e`](https://github.com/wellyshen/react-cool-form/commit/d6d254e17d22ef56e5392a840b20eda4e221e624) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update example\n\n## 0.0.37\n\n### Patch Changes\n\n- [`ccb2ef9`](https://github.com/wellyshen/react-cool-form/commit/ccb2ef96f94e99e44c19bc9c95af266443ffa4c5) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): refine submit()\n\n* [`0ed35f0`](https://github.com/wellyshen/react-cool-form/commit/0ed35f0f770ce2eff703e392b3049268a4b8b581) [#137](https://github.com/wellyshen/react-cool-form/pull/137) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): add excludeFields config\n\n- [`6f034af`](https://github.com/wellyshen/react-cool-form/commit/6f034afd65fcd561ba9e1dbe59c60b7c8e4133df) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(package.json): update example\n\n* [`130e476`](https://github.com/wellyshen/react-cool-form/commit/130e4769a1a8dd4e4dee4d075801fbf0e02dfb2b) [#136](https://github.com/wellyshen/react-cool-form/pull/136) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): change iControlledFields config to iControlFields\n\n## 0.0.36\n\n### Patch Changes\n\n- [`a5ee7d9`](https://github.com/wellyshen/react-cool-form/commit/a5ee7d9784038f200f4065ead3728cfdc09f0689) [#132](https://github.com/wellyshen/react-cool-form/pull/132) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): change the ignoreFields to iControlledFields\n\n* [`957de35`](https://github.com/wellyshen/react-cool-form/commit/957de35fa996357d90ac0c017a4e09316a1f8dca) [#134](https://github.com/wellyshen/react-cool-form/pull/134) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): set all fields to touched when submitting\n\n## 0.0.35\n\n### Patch Changes\n\n- [`9134efa`](https://github.com/wellyshen/react-cool-form/commit/9134efa42c2444874f1e24f2efc80e38906fb76f) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update the example section\n\n* [`704e67c`](https://github.com/wellyshen/react-cool-form/commit/704e67cb22c70081e4b47a7ccacd2d80a8689b10) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update example\n\n- [`72c3aaa`](https://github.com/wellyshen/react-cool-form/commit/72c3aaa08cba5fb130f56dccdd72c6f55491f051) [#129](https://github.com/wellyshen/react-cool-form/pull/129) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): remove setFieldTouchedMaybeValidate()\n\n* [`428c80b`](https://github.com/wellyshen/react-cool-form/commit/428c80baa3b917c4bdf8b12d30e9892c56cbd169) [#131](https://github.com/wellyshen/react-cool-form/pull/131) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): cache previous built-in errors for better DX\n\n## 0.0.34\n\n### Patch Changes\n\n- [`40c5e05`](https://github.com/wellyshen/react-cool-form/commit/40c5e057ebde404a00794b36045f7cc823413972) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): enhance the readability of setFieldTouchedMaybeValidate()\n\n* [`9b451a4`](https://github.com/wellyshen/react-cool-form/commit/9b451a49e1cb913135818b749c88440441fd4990) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): update example\n\n## 0.0.33\n\n### Patch Changes\n\n- [`e916e57`](https://github.com/wellyshen/react-cool-form/commit/e916e573177c9c9e554d48411ad7ed531619448c) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): correct example\n\n## 0.0.32\n\n### Patch Changes\n\n- [`732b593`](https://github.com/wellyshen/react-cool-form/commit/732b593ad77175e4e866cf6439abc0772b1c118c) Thanks [@wellyshen](https://github.com/wellyshen)! - chore: add more github templates\n\n* [`c8c715d`](https://github.com/wellyshen/react-cool-form/commit/c8c715de6779da10b1563baaa2fbccea69a57f03) [#124](https://github.com/wellyshen/react-cool-form/pull/124) Thanks [@wellyshen](https://github.com/wellyshen)! - chore: use bundlesize\n\n- [`495f275`](https://github.com/wellyshen/react-cool-form/commit/495f275851858aafd0429e5222aa4d0b52502088) Thanks [@wellyshen](https://github.com/wellyshen)! - docs: update readme\n\n* [`908f7fe`](https://github.com/wellyshen/react-cool-form/commit/908f7fe0500c7ccfdb767737d35fbcc9bdcf5fb4) Thanks [@wellyshen](https://github.com/wellyshen)! - chore: adjust package commands and rollup config\n\n- [`e3e0e73`](https://github.com/wellyshen/react-cool-form/commit/e3e0e73a568456228b28a489d133074b74954593) [#126](https://github.com/wellyshen/react-cool-form/pull/126) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): correct the logic of avoid double validating of setFieldTouched()\n\n## 0.0.31\n\n### Patch Changes\n\n- [`abc5239`](https://github.com/wellyshen/react-cool-form/commit/abc52396e0036db192f12b0e89c1e56320de1d1f) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): change runWithLowPrioirty() to requestIdleCallback()\n\n## 0.0.30\n\n### Patch Changes\n\n- [`1621ce1`](https://github.com/wellyshen/react-cool-form/commit/1621ce1b88c5027b1feef37e87dbe7a06fb44060) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): move runWithLowPrioirty into useForm\n\n## 0.0.29\n\n### Patch Changes\n\n- [`948807c`](https://github.com/wellyshen/react-cool-form/commit/948807c6f045948f1fb033052d8984364580f0bb) [#120](https://github.com/wellyshen/react-cool-form/pull/120) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): use requestIdleCallback instead of scheduler\n\n## 0.0.28\n\n### Patch Changes\n\n- [`d935f68`](https://github.com/wellyshen/react-cool-form/commit/d935f68da3e734aaec792493c1418784e32c9a77) [#111](https://github.com/wellyshen/react-cool-form/pull/111) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): correct dynamic fields behavior\n\n## 0.0.27\n\n### Patch Changes\n\n- [`0ceb94a`](https://github.com/wellyshen/react-cool-form/commit/0ceb94a72259492d802f23e0bd288085c86df7a2) [#108](https://github.com/wellyshen/react-cool-form/pull/108) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): auto add/remove fields\n\n## 0.0.26\n\n### Patch Changes\n\n- [`6821f0d`](https://github.com/wellyshen/react-cool-form/commit/6821f0de12a40a607139c8f4b6c74dd366d6c3d0) [#106](https://github.com/wellyshen/react-cool-form/pull/106) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): correct number data type\n\n## 0.0.24\n\n### Patch Changes\n\n- [`8037f98`](https://github.com/wellyshen/react-cool-form/commit/8037f9869a52ccc08742064cf7c0f63819da4e83) [#103](https://github.com/wellyshen/react-cool-form/pull/103) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): adjust the UX of defaultValues, reset(), and setValues()\n\n* [`0890b1c`](https://github.com/wellyshen/react-cool-form/commit/0890b1cff52841df1827a9a62c7ab646af2556cf) [#105](https://github.com/wellyshen/react-cool-form/pull/105) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): move ignoreFieldsRef to getFields()\n\n## 0.0.23\n\n### Patch Changes\n\n- [`3d308f2`](https://github.com/wellyshen/react-cool-form/commit/3d308f2fc92470004820ee629a8756f50ce2be82) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): use the default value of checkbox as the value of checkbox-group\n\n* [`7a0d9cb`](https://github.com/wellyshen/react-cool-form/commit/7a0d9cb2aa07b91bccaef4cda71adfcc9cef4708) [#101](https://github.com/wellyshen/react-cool-form/pull/101) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): enable React defaultValue\n\n- [`d203e07`](https://github.com/wellyshen/react-cool-form/commit/d203e07babf1c5ded1e152e85ccd30b3c68f4c3f) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): use empty object as the fallback of initialValues\n\n* [`f213a2d`](https://github.com/wellyshen/react-cool-form/commit/f213a2d524faced26b693a2bdf6e3d2f9a6a7b5c) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor: remove is-key logic\n\n## 0.0.22\n\n### Patch Changes\n\n- [`af29dfd`](https://github.com/wellyshen/react-cool-form/commit/af29dfd485d6450a2d7613d7cf1e09f433fb08e2) [#99](https://github.com/wellyshen/react-cool-form/pull/99) Thanks [@wellyshen](https://github.com/wellyshen)! - avoid un-necessary re-render & strip hidden input from element checking\n\n* [`4f08865`](https://github.com/wellyshen/react-cool-form/commit/4f088655f9593ed011393e092d73982711dd89ec) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): re-parse fields when both add and remove nodes\n\n- [`19e5584`](https://github.com/wellyshen/react-cool-form/commit/19e55844491388b4b8ff6e454e2345d4a3b58484) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): unset dirtyField if not dirty\n\n## 0.0.21\n\n### Patch Changes\n\n- [`c9ca4b9`](https://github.com/wellyshen/react-cool-form/commit/c9ca4b9135e6bc2208e0e79fe459e896376df719) [#96](https://github.com/wellyshen/react-cool-form/pull/96) Thanks [@wellyshen](https://github.com/wellyshen)! - feat: expose `get()` and `set()` utility functions\n\n## 0.0.20\n\n### Patch Changes\n\n- [`27a6c50`](https://github.com/wellyshen/react-cool-form/commit/27a6c50920fee1089cea1e913b32688b523b50f0) [#93](https://github.com/wellyshen/react-cool-form/pull/93) Thanks [@wellyshen](https://github.com/wellyshen)! - feat: use unset for clear error\n\n## 0.0.19\n\n### Patch Changes\n\n- [`a77b052`](https://github.com/wellyshen/react-cool-form/commit/a77b052f250eff3e80cea75918ab20529dbf4346) [#91](https://github.com/wellyshen/react-cool-form/pull/91) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor: use reset() instead of resetStateRef()\n\n## 0.0.18\n\n### Patch Changes\n\n- [`7ec087a`](https://github.com/wellyshen/react-cool-form/commit/7ec087a08ab2b3e1e4c41eb2389aeafcad8019c2) [#89](https://github.com/wellyshen/react-cool-form/pull/89) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): remove un-necessary for loop from Mutation Observer\n\n## 0.0.17\n\n### Patch Changes\n\n- [`2a40058`](https://github.com/wellyshen/react-cool-form/commit/2a4005814a1a2e4a9ddd82e7ae366e8896ed1fab) [#87](https://github.com/wellyshen/react-cool-form/pull/87) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): built-in handle-submit and handle-reset for you :)\n\n* [`ab72fdb`](https://github.com/wellyshen/react-cool-form/commit/ab72fdb9a89d3c67a78d6e427cb022859c95170f) [#86](https://github.com/wellyshen/react-cool-form/pull/86) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): support built-in validation\n\n- [`e620376`](https://github.com/wellyshen/react-cool-form/commit/e620376bb4d178575f2647223491412eb8353006) Thanks [@wellyshen](https://github.com/wellyshen)! - chore: move configs out of package.json\n\n## 0.0.16\n\n### Patch Changes\n\n- [`f8c31f1`](https://github.com/wellyshen/react-cool-form/commit/f8c31f1f535d4cbe76414518242ab3b8963283bc) [#84](https://github.com/wellyshen/react-cool-form/pull/84) Thanks [@wellyshen](https://github.com/wellyshen)! - perf(useForm): remove setFieldTouchedIfNeeded() to reduce bundle size\n\n* [`3a39bf1`](https://github.com/wellyshen/react-cool-form/commit/3a39bf1a3004ddf363307f511af3d5a4356a8d40) [#83](https://github.com/wellyshen/react-cool-form/pull/83) Thanks [@wellyshen](https://github.com/wellyshen)! - perf(useForm): reduce bundle size by simplying code\n\n## 0.0.15\n\n### Patch Changes\n\n- [`cd173f5`](https://github.com/wellyshen/react-cool-form/commit/cd173f54442321563605db7f2d64c670a7c95b44) [#80](https://github.com/wellyshen/react-cool-form/pull/80) Thanks [@wellyshen](https://github.com/wellyshen)! - upgrade: react v16 to v17\n\n* [`b54bd81`](https://github.com/wellyshen/react-cool-form/commit/b54bd814bc72b2eaf45e14ef8120f574dd71d975) [#81](https://github.com/wellyshen/react-cool-form/pull/81) Thanks [@wellyshen](https://github.com/wellyshen)! - ci: adjust the check-and-test action\n\n## 0.0.14\n\n### Patch Changes\n\n- [`d23d838`](https://github.com/wellyshen/react-cool-form/commit/d23d838f7520c28a93ef7f0922e187fadfa8e5eb) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor: change `getFromState()` to `getState()`\n\n## 0.0.13\n\n### Patch Changes\n\n- [`087f8a4`](https://github.com/wellyshen/react-cool-form/commit/087f8a4b3ae53df325fbc2afe9ce752cc8762301) [#76](https://github.com/wellyshen/react-cool-form/pull/76) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor: adjust file structure\n\n* [`d456e8e`](https://github.com/wellyshen/react-cool-form/commit/d456e8e4dd49c1f03da73c220368d24a68f369e8) [#74](https://github.com/wellyshen/react-cool-form/pull/74) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): add ignoreFields config\n\n## 0.0.12\n\n### Patch Changes\n\n- [`9bc2680`](https://github.com/wellyshen/react-cool-form/commit/9bc2680139f543c2cf8ecbdcf78e88696137f09d) [#72](https://github.com/wellyshen/react-cool-form/pull/72) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): adjust export format\n\n## 0.0.11\n\n### Patch Changes\n\n- [`ccbbe64`](https://github.com/wellyshen/react-cool-form/commit/ccbbe641dd4fc0975d9597cee394a3c4d797510c) [#70](https://github.com/wellyshen/react-cool-form/pull/70) Thanks [@wellyshen](https://github.com/wellyshen)! - fix: correct UMD format\n\n## 0.0.10\n\n### Patch Changes\n\n- [`34bb0c1`](https://github.com/wellyshen/react-cool-form/commit/34bb0c18c29c2e5c5d4378c7560d369f27381832) [#68](https://github.com/wellyshen/react-cool-form/pull/68) Thanks [@wellyshen](https://github.com/wellyshen)! - feat: support UMD format\n\n## 0.0.9\n\n### Patch Changes\n\n- [`0aefe6a`](https://github.com/wellyshen/react-cool-form/commit/0aefe6a3d2fe9e8dd326e360a18c88c003447823) [#67](https://github.com/wellyshen/react-cool-form/pull/67) Thanks [@wellyshen](https://github.com/wellyshen)! - feat(useForm): accept function as the values argv of the reset method\n\n* [`8a8f978`](https://github.com/wellyshen/react-cool-form/commit/8a8f9782abf18e8d97fa804bd45825cb560eeb9b) [#65](https://github.com/wellyshen/react-cool-form/pull/65) Thanks [@wellyshen](https://github.com/wellyshen)! - refactor(useForm): disabled the watch mode of getFormState() for event & remove un-necessary variable\n\n## 0.0.8\n\n### Patch Changes\n\n- [`1815a89`](https://github.com/wellyshen/react-cool-form/commit/1815a89be457826aa55ec37e08123b0a237e60e3) [#62](https://github.com/wellyshen/react-cool-form/pull/62) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): add milestone section\n\n* [`d40937d`](https://github.com/wellyshen/react-cool-form/commit/d40937d12b706c642776d0468d398f409b3bf313) [#63](https://github.com/wellyshen/react-cool-form/pull/63) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): elimiate useLayoutEffect warning in SSR\n\n## 0.0.7\n\n### Patch Changes\n\n- [`598f2f7`](https://github.com/wellyshen/react-cool-form/commit/598f2f721a418cbda96df3931e3cfcc8caeaa5f6) [#60](https://github.com/wellyshen/react-cool-form/pull/60) Thanks [@wellyshen](https://github.com/wellyshen)! - fix(useForm): correct the value of dynamic fields\n\n## 0.0.6\n\n### Patch Changes\n\n- [`6ff974e`](https://github.com/wellyshen/react-cool-form/commit/6ff974ee206aa498ccf3731c065b4bf08dc2e8b2) [#59](https://github.com/wellyshen/react-cool-form/pull/59) Thanks [@wellyshen](https://github.com/wellyshen)! - chore(package.json): adjust description and command\n\n* [`3359813`](https://github.com/wellyshen/react-cool-form/commit/33598136ca8c78d2d0a96ddd09c860caa657339b) [#57](https://github.com/wellyshen/react-cool-form/pull/57) Thanks [@wellyshen](https://github.com/wellyshen)! - docs: update README\n\n## 0.0.5\n\n### Patch Changes\n\n- [`ade598e`](https://github.com/wellyshen/react-cool-form/commit/ade598ece6caa28026363100311b4a9d0ed14035) [#55](https://github.com/wellyshen/react-cool-form/pull/55) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): adjust layout\n\n## 0.0.4\n\n### Patch Changes\n\n- [`556bba9`](https://github.com/wellyshen/react-cool-form/commit/556bba90ebd88076e0a02548d899a31d27e26958) [#54](https://github.com/wellyshen/react-cool-form/pull/54) Thanks [@wellyshen](https://github.com/wellyshen)! - docs(readme): edit title section\n\n* [`014f148`](https://github.com/wellyshen/react-cool-form/commit/014f1485d748fbb4332c5cf7e168bb76bce15330) [#51](https://github.com/wellyshen/react-cool-form/pull/51) Thanks [@wellyshen](https://github.com/wellyshen)! - chore(package.json): edit description\n\n- [`ad9b72a`](https://github.com/wellyshen/react-cool-form/commit/ad9b72a21a8ae7d95489313336241d504d6645d2) [#53](https://github.com/wellyshen/react-cool-form/pull/53) Thanks [@wellyshen](https://github.com/wellyshen)! - fix: empty package\n\n## 0.0.3\n\n### Patch Changes\n\n- [`5c397c0`](https://github.com/wellyshen/react-cool-form/commit/5c397c035e0955d1be46a8f794879da459d36982) [#49](https://github.com/wellyshen/react-cool-form/pull/49) Thanks [@wellyshen](https://github.com/wellyshen)! - chore(package.json): add keyword\n\n* [`5c397c0`](https://github.com/wellyshen/react-cool-form/commit/5c397c035e0955d1be46a8f794879da459d36982) [#49](https://github.com/wellyshen/react-cool-form/pull/49) Thanks [@wellyshen](https://github.com/wellyshen)! - chore(package.json): add description\n\n- [`5c397c0`](https://github.com/wellyshen/react-cool-form/commit/5c397c035e0955d1be46a8f794879da459d36982) [#49](https://github.com/wellyshen/react-cool-form/pull/49) Thanks [@wellyshen](https://github.com/wellyshen)! - chore(package.json): edit keyword\n\n* [`5c397c0`](https://github.com/wellyshen/react-cool-form/commit/5c397c035e0955d1be46a8f794879da459d36982) [#49](https://github.com/wellyshen/react-cool-form/pull/49) Thanks [@wellyshen](https://github.com/wellyshen)! - chore(package.json): add keyword\n\n- [`5c397c0`](https://github.com/wellyshen/react-cool-form/commit/5c397c035e0955d1be46a8f794879da459d36982) [#49](https://github.com/wellyshen/react-cool-form/pull/49) Thanks [@wellyshen](https://github.com/wellyshen)! - chore(package.json): edit keyword\n\n* [`5c397c0`](https://github.com/wellyshen/react-cool-form/commit/5c397c035e0955d1be46a8f794879da459d36982) [#49](https://github.com/wellyshen/react-cool-form/pull/49) Thanks [@wellyshen](https://github.com/wellyshen)! - chore(package.json): add keyword\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n- Demonstrating empathy and kindness toward other people\n- Being respectful of differing opinions, viewpoints, and experiences\n- Giving and gracefully accepting constructive feedback\n- Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n- Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n- The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n- Trolling, insulting or derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\nhivoid19@gmail.com.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\n[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][mozilla coc].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n[https://www.contributor-covenant.org/faq][faq]. Translations are available\nat [https://www.contributor-covenant.org/translations][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html\n[mozilla coc]: https://github.com/mozilla/diversity\n[faq]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to React Cool Form\n\nWhen contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.\n\nPlease note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.\n\n> Working on your first Pull Request? You can learn how from [this free video series](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github).\n\n## Pull Request Process\n\n1. Fork the repository and create your branch from `master`.\n2. Run `yarn` to install dependencies.\n3. If you’ve fixed a bug or added code that should be tested.\n4. Ensure the test suite passes by running `yarn test`.\n5. Update related [documents](docs) with details of changes to the interface.\n6. Update related [examples](examples) if needed.\n7. Make sure your code lints by running `yarn lint`.\n8. Run `yarn changeset` to [add a changeset](https://github.com/atlassian/changesets/blob/master/docs/adding-a-changeset.md).\n\n## Development Workflow\n\nYou can test new features or debug an issue by the way that I'm using.\n\n1. Run `yarn link-pkg` to link the package into the [app directory](app).\n2. Run `yarn start` to create an `ESM` build and type definition file by `rollup` watch mode.\n3. Access the [app directory](app).\n4. In the **app directory**, run `yarn link-pkg` to link with the package then run `yarn start:dev` to start development.\n5. Try something cool via the [Playground](app/src/Playground).\n\n## Useful Commands\n\nThere're several useful commands that you can use during the development:\n\n- `yarn link-pkg` links the package into the [app directory](app). You can develop or debug it via the [playground](app/src/App).\n- `yarn start` creates a `dist` folder with an `ESM` build and type definition file by `rollup` watch mode.\n- `yarn build:dev` creates a `dist` folder with an `ESM` build and type definition file for development.\n- `yarn build:prod` creates a `dist` folder with package builds (`CJS`, `ESM`, and `UMD`) and type definition file. You can test the package locally via `yarn link-pkg` or [yarn link](https://yarnpkg.com/lang/en/docs/cli/link).\n- `yarn changeset` [adds a changeset](https://github.com/atlassian/changesets/blob/master/docs/adding-a-changeset.md).\n- `yarn lint:code` lints all `.js` and `.tsx?` files.\n- `yarn lint:type` runs the [TypeScript](https://www.typescriptlang.org) type-checks.\n- `yarn lint:format` formats all files except the file list of `.prettierignore`.\n- `yarn lint` lints `code`, `type`, and `format`.\n- `yarn test` runs the complete test suite.\n- `yarn test:watch` runs an interactive test watcher (helpful in development).\n- `yarn test:cov` runs the complete test suite with coverage report.\n- `yarn size` checks the bundle size of each format.\n- `yarn clean:build` deletes the `dist` build folder.\n- `yarn clean:size`: deletes the `.size-snapshot.json` file.\n- `yarn clean:cov` deletes the `coverage` report folder.\n- `yarn clean` deletes the build, coverage, and size snapshot.\n\n## Style Guide\n\nWe use [ESLint](https://eslint.org), [StyleLint](https://stylelint.io) and [Prettier](https://prettier.io) for code style and formatting. Run `yarn lint` after making any changes to the code. Then, our linter will catch most issues that might exist in your code.\n\nHowever, there are still some styles that the linter cannot pick up. If you are unsure about something, looking at [Airbnb’s Style Guide](https://github.com/airbnb/javascript) will guide you in the right direction.\n\n## License\n\nBy contributing to React Cool Form, you agree that your contributions will be licensed under its MIT license.\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2021 Welly Shen\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "> ⚠️ Thank you for supporting me, this library isn't maintained anymore. Please consider other libraries.\n\n<p align=\"center\">\n  <br/><br/>\n  <a href=\"https://react-cool-form.netlify.app\" title=\"React Cool Form\"><img src=\"https://react-cool-form.netlify.app/img/logo-github.svg\" width=\"300px\" alt=\"React Cool Form\"></a>\n</p>\n\n<p align=\"center\">React hooks for forms state and validation, less code more performant.</p>\n\n<div align=\"center\">\n\n[![npm version](https://img.shields.io/npm/v/react-cool-form?style=flat-square)](https://www.npmjs.com/package/react-cool-form)\n[![npm downloads](https://img.shields.io/npm/dt/react-cool-form?style=flat-square)](https://www.npmtrends.com/react-cool-form)\n[![coverage status](https://img.shields.io/coveralls/github/wellyshen/react-cool-form?style=flat-square)](https://coveralls.io/github/wellyshen/react-cool-form?branch=master)\n[![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors-)\n[![netlify deploy](https://img.shields.io/netlify/3c201e27-b611-4512-b827-9523af7a1ae5?style=flat-square)](https://app.netlify.com/sites/react-cool-form/deploys)\n\n</div>\n\n## Features\n\n- 🎣 [Easy to use](https://react-cool-form.netlify.app/docs/getting-started/integration-an-existing-form), React Cool Form is [a set of React hooks](https://react-cool-form.netlify.app/docs/api-reference/use-form) that helps you conquer all kinds of forms.\n- 🗃 Manages [dynamic](https://react-cool-form.netlify.app/docs/examples/conditional-fields) and [complex](https://react-cool-form.netlify.app/docs/getting-started/complex-structures) form data without hassle.\n- 🪄 Manages [arrays and lists](https://react-cool-form.netlify.app/docs/getting-started/arrays-and-lists) data like a master.\n- 🚦 Supports [built-in](https://react-cool-form.netlify.app/docs/getting-started/validation-guide#built-in-validation), [form-level](https://react-cool-form.netlify.app/docs/getting-started/validation-guide#form-level-validation), and [field-level](https://react-cool-form.netlify.app/docs/getting-started/validation-guide#field-level-validation) validation.\n- 🚀 Highly performant, [minimizes the number of re-renders](https://react-cool-form.netlify.app#performance-matters) for you.\n- 🧱 Seamless integration with existing HTML form inputs or [3rd-party UI libraries](https://react-cool-form.netlify.app/docs/getting-started/3rd-party-ui-libraries).\n- 🎛 Super flexible [API](https://react-cool-form.netlify.app/docs/api-reference/use-form) design, built with [DX and UX](https://react-cool-form.netlify.app/docs) in mind.\n- 🔩 Provides useful [utility functions](https://react-cool-form.netlify.app/docs/api-reference/utility-functions) to boost forms development.\n- 📜 Supports [TypeScript](https://react-cool-form.netlify.app/docs/getting-started/typescript-support) type definition.\n- ☁️ Server-side rendering compatibility.\n- 🦔 A [tiny size](https://react-cool-form.netlify.app/docs/getting-started/bundle-size-overview) ([~ 7.1kB gizpped](https://bundlephobia.com/result?p=react-cool-form)) library but powerful.\n\n## [Docs](https://react-cool-form.netlify.app)\n\nSee the documentation at [react-cool-form.netlify.app](https://react-cool-form.netlify.app) for more information about using React Cool Form!\n\nFrequently viewed docs:\n\n- [Getting Started](https://react-cool-form.netlify.app/docs)\n- [Examples](https://react-cool-form.netlify.app/docs/examples/basic)\n- [API Reference](https://react-cool-form.netlify.app/docs/api-reference/use-form)\n\n## Quick Start\n\nTo use React Cool Form, you must use `react@16.8.0` or greater which includes hooks. This package is distributed via [npm](https://www.npmjs.com/package/react-cool-form).\n\n```sh\n$ yarn add react-cool-form\n# or\n$ npm install --save react-cool-form\n```\n\nHere's the basic concept of how it rocks:\n\n[![Edit RCF - Quick start](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-quick-start-j8p1l?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm } from \"react-cool-form\";\n\nconst Field = ({ label, id, error, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n    {error && <p>{error}</p>}\n  </div>\n);\n\nconst App = () => {\n  const { form, use } = useForm({\n    // (Strongly advise) Provide the default values\n    defaultValues: { username: \"\", email: \"\", password: \"\" },\n    // The event only triggered when the form is valid\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  // We can enable the \"errorWithTouched\" option to filter the error of an un-blurred field\n  // Which helps the user focus on typing without being annoyed by the error message\n  const errors = use(\"errors\", { errorWithTouched: true }); // Default is \"false\"\n\n  return (\n    <form ref={form} noValidate>\n      <Field\n        label=\"Username\"\n        id=\"username\"\n        name=\"username\"\n        // Support built-in validation\n        required\n        error={errors.username}\n      />\n      <Field\n        label=\"Email\"\n        id=\"email\"\n        name=\"email\"\n        type=\"email\"\n        required\n        error={errors.email}\n      />\n      <Field\n        label=\"Password\"\n        id=\"password\"\n        name=\"password\"\n        type=\"password\"\n        required\n        minLength={8}\n        error={errors.password}\n      />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n✨ Pretty easy right? React Cool Form is more powerful than you think. Let's [explore it](https://react-cool-form.netlify.app) now!\n\n## Articles / Blog Posts \n\n> 💡 If you have written any blog post or article about React Cool Form, please open a PR to add it here.\n\n- Featured on [React Status #245](https://react.statuscode.com/issues/245).\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tr>\n    <td align=\"center\"><a href=\"http://wellyshen.com\"><img src=\"https://avatars.githubusercontent.com/u/21308003?v=4?s=100\" width=\"100px;\" alt=\"\"/><br /><sub><b>Welly</b></sub></a><br /><a href=\"#ideas-wellyshen\" title=\"Ideas, Planning, & Feedback\">🤔</a> <a href=\"https://github.com/wellyshen/react-cool-form/commits?author=wellyshen\" title=\"Code\">💻</a> <a href=\"https://github.com/wellyshen/react-cool-form/commits?author=wellyshen\" title=\"Documentation\">📖</a> <a href=\"#infra-wellyshen\" title=\"Infrastructure (Hosting, Build-Tools, etc)\">🚇</a> <a href=\"#maintenance-wellyshen\" title=\"Maintenance\">🚧</a></td>\n    <td align=\"center\"><a href=\"https://github.com/Chris-James\"><img src=\"https://avatars.githubusercontent.com/u/4596428?v=4?s=100\" width=\"100px;\" alt=\"\"/><br /><sub><b>Chris</b></sub></a><br /><a href=\"https://github.com/wellyshen/react-cool-form/issues?q=author%3AChris-James\" title=\"Bug reports\">🐛</a></td>\n  </tr>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nUse this section to tell people about which versions of your project are\ncurrently being supported with security updates.\n\n| Version | Supported          |\n| ------- | ------------------ |\n| 5.1.x   | :white_check_mark: |\n| 5.0.x   | :x:                |\n| 4.0.x   | :white_check_mark: |\n| < 4.0   | :x:                |\n\n## Reporting a Vulnerability\n\nUse this section to tell people how to report a vulnerability.\n\nTell them where to go, how often they can expect to get an update on a\nreported vulnerability, what to expect if the vulnerability is accepted or\ndeclined, etc.\n"
  },
  {
    "path": "app/.eslintignore",
    "content": "build"
  },
  {
    "path": "app/.eslintrc.js",
    "content": "module.exports = {\n  extends: [\"react-app\", \"welly\"],\n  rules: { \"react/react-in-jsx-scope\": \"off\" },\n};\n"
  },
  {
    "path": "app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\nnode_modules\n.pnp\n.pnp.js\n\n# testing\ncoverage\n\n# production\nbuild\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n.eslintcache\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "app/.prettierignore",
    "content": "# testing\ncoverage\n\n# production\nbuild\n\n# misc\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "app/.stylelintrc.js",
    "content": "module.exports = {\n  extends: [\"stylelint-config-standard\", \"stylelint-config-prettier\"],\n  ignoreFiles: [\"build/**/*.css\"],\n};\n"
  },
  {
    "path": "app/README.md",
    "content": "# App\n\n🧪 A place for trying something interesting.\n"
  },
  {
    "path": "app/package.json",
    "content": "{\n  \"name\": \"rcf-app\",\n  \"private\": true,\n  \"scripts\": {\n    \"link-pkg\": \"yarn link 'react-cool-form'\",\n    \"start:auto\": \"react-scripts start\",\n    \"start:dev\": \"REACT_APP_ENV=dev react-scripts start\",\n    \"start:prod\": \"yarn build && serve -s build\",\n    \"build\": \"react-scripts build\",\n    \"lint\": \"run-s lint:*\",\n    \"lint:code\": \"eslint --fix . --ext .js,.ts,.tsx\",\n    \"lint:type\": \"tsc\",\n    \"lint:style\": \"stylelint --fix \\\"**/*.{css,ts,tsx}\\\"\",\n    \"lint:format\": \"prettier -w . -u --loglevel silent\",\n    \"clean\": \"rimraf build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"dependencies\": {\n    \"@emotion/react\": \"^11.4.0\",\n    \"@types/node\": \"^16.4.1\",\n    \"@types/react\": \"^17.0.14\",\n    \"@types/react-dom\": \"^17.0.9\",\n    \"normalize.css\": \"^8.0.1\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"5.0.0\",\n    \"typescript\": \"^4.3.5\"\n  },\n  \"devDependencies\": {\n    \"eslint-config-welly\": \"^1.13.0\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"prettier\": \"^2.3.2\",\n    \"rimraf\": \"^3.0.2\",\n    \"serve\": \"^13.0.2\",\n    \"stylelint\": \"^13.13.1\",\n    \"stylelint-config-prettier\": \"^8.0.2\",\n    \"stylelint-config-standard\": \"^22.0.0\"\n  }\n}\n"
  },
  {
    "path": "app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"%PUBLIC_URL%/favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta\n      name=\"description\"\n      content=\"React hooks for forms state and validation, less code more performant.\"\n    />\n    <link rel=\"apple-touch-icon\" href=\"%PUBLIC_URL%/logo192.png\" />\n    <!--\n      manifest.json provides metadata used when your web app is installed on a\n      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\" />\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <link\n      href=\"https://fonts.googleapis.com/css2?family=Roboto&display=swap\"\n      rel=\"stylesheet\"\n    />\n    <title>React Cool Form</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "app/public/manifest.json",
    "content": "{\n  \"short_name\": \"REACT COOL IMG\",\n  \"name\": \"REACT COOL IMG\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    },\n    {\n      \"src\": \"logo192.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"192x192\"\n    },\n    {\n      \"src\": \"logo512.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"512x512\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "app/public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n"
  },
  {
    "path": "app/src/App/index.tsx",
    "content": "import { Global, css } from \"@emotion/react\";\nimport normalize from \"normalize.css\";\n\nimport Playground from \"../Playground\";\nimport Automation from \"../Automation\";\nimport { root } from \"./styles\";\n\nexport default (): JSX.Element => (\n  <>\n    <Global\n      styles={css`\n        ${normalize}\n        ${root}\n      `}\n    />\n    {process.env.REACT_APP_ENV === \"dev\" ? <Playground /> : <Automation />}\n  </>\n);\n"
  },
  {
    "path": "app/src/App/styles.ts",
    "content": "import { css } from \"@emotion/react\";\n\n// eslint-disable-next-line import/prefer-default-export\nexport const root = css`\n  body {\n    font-family: \"Roboto\", sans-serif;\n  }\n`;\n"
  },
  {
    "path": "app/src/Automation/index.tsx",
    "content": "const Automation = (): JSX.Element => <h1>Automation</h1>;\n\nexport default Automation;\n"
  },
  {
    "path": "app/src/Playground/index.tsx",
    "content": "/* eslint-disable no-console */\n\nimport { useForm } from \"react-cool-form\";\n\nexport default () => {\n  const { form, runValidation } = useForm({\n    // validate: () => ({ foo: \"Required\" }),\n    focusOnError: [\"foo\"],\n  });\n\n  return (\n    <>\n      <form ref={form} noValidate>\n        <input name=\"foo\" required />\n        <input name=\"bar\" required />\n        {/* <input type=\"submit\" /> */}\n      </form>\n      <button type=\"button\" onClick={() => runValidation([\"bar\"])}>\n        Validate\n      </button>\n    </>\n  );\n};\n"
  },
  {
    "path": "app/src/index.tsx",
    "content": "import { StrictMode } from \"react\";\nimport ReactDOM from \"react-dom\";\n\nimport App from \"./App\";\n\nReactDOM.render(\n  <StrictMode>\n    <App />\n  </StrictMode>,\n  document.getElementById(\"root\")\n);\n"
  },
  {
    "path": "app/src/react-app-env.d.ts",
    "content": "/// <reference types=\"react-scripts\" />\n/// <reference types=\"@emotion/react/types/css-prop\" />\n"
  },
  {
    "path": "app/src/types/index.d.ts",
    "content": "declare module \"*.css\";\n"
  },
  {
    "path": "app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "babel.config.json",
    "content": "{\n  \"presets\": [\n    [\n      \"@babel/env\",\n      {\n        \"loose\": true,\n        \"exclude\": [\n          \"@babel/plugin-transform-async-to-generator\",\n          \"@babel/plugin-transform-regenerator\"\n        ]\n      }\n    ],\n    \"@babel/typescript\",\n    \"@babel/react\"\n  ]\n}\n"
  },
  {
    "path": "bundlesize.config.json",
    "content": "{\n  \"files\": [\n    {\n      \"path\": \"dist/index.umd.production.min.js\",\n      \"maxSize\": \"7.2 kB\"\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/api-reference/use-controlled.md",
    "content": "---\nid: use-controlled\ntitle: useControlled\n---\n\nThis hook allows us to integrate with an existing component (usually a [controlled component](https://reactjs.org/docs/forms.html#controlled-components)) or 3rd-party UI library in React Cool Form. With this hook, we can easily to create a reusable controller component to fulfill our needs. See the [useControlled Hook](../getting-started/3rd-party-ui-libraries#2-usecontrolled-hook) to learn more.\n\n:::note\nWhen working with [conditional fields](../examples/conditional-fields), please ensure the hook is wrapped in a component.\n:::\n\n```js\nconst [fieldProps, meta] = useControlled(name, config);\n```\n\n## Name\n\n`string`\n\nThe name of the field. We must provide it when using this hook.\n\n## Config\n\nAn `object` with the following options:\n\n### formId\n\n`string`\n\nThe [corresponding ID](./use-form#id) of the `useForm` hook. We only need it when using multiple form hooks at the same time.\n\n### defaultValue\n\n`string`\n\nThe default value of the field. Useful for dealing with the case of [conditional fields](../examples/conditional-fields).\n\n### validation\n\n`(value: any, values: FormValues) => any | Promise<any>`\n\nA synchronous/asynchronous function that is used for the [field-level validation](../getting-started/validation-guide#field-level-validation).\n\n### parse\n\n`(...args: any[]) => any`\n\nA function that takes the event object (or parameters) of the target component's `onChange` handler and parses the value of the field that you want to store into the [form state](../getting-started/form-state#about-the-form-state). Useful for data type converting.\n\n### format\n\n`(value: any) => any`\n\nA function that takes the field's value from the [form state](../getting-started/form-state#about-the-form-state) and formats the value to give to the field. Usually used in conjunction with `parse`.\n\n### errorWithTouched\n\n`boolean`\n\nEnable/disable the feature of **filtering untouched errors**, which can help the user focus on typing without being annoyed by the error message. Default is `false`.\n\n```js\n// Current state: { errors: { foo: \"Required\" }, touched: {} }\n// Returns \"Required\"\nconst [, { error }] = useControlled(\"foo\");\n\n// Current state: { errors: { foo: \"Required\" }, touched: {} }\n// Returns undefined\nconst [, { error }] = useControlled(\"foo\", { errorWithTouched: true });\n\n// Current state: { errors: { foo: \"Required\" }, touched: { foo: true } }\n// Returns \"Required\"\nconst [, { error }] = useControlled(\"foo\", { errorWithTouched: true });\n```\n\n### ...restProps\n\nAny other props that will be spread into the `fieldProps`.\n\n## Field Props\n\nAn `object` with the following properties:\n\n### name\n\n`string`\n\nThe name of the field.\n\n### value\n\n`any`\n\nThe value of the field.\n\n### onChange\n\n`(...event: any[]) => void`\n\nAn event handler called when the field's value changed.\n\n### onBlur\n\n`(e: React.FocusEvent) => void`\n\nAn event handler called when the field loses focus.\n\n### ...restProps\n\nAny other props that were passed to the `config`.\n\n## Meta\n\nAn `object` with the following properties:\n\n### error\n\n`string | undefined`\n\nThe current validation error of the field.\n\n### isTouched\n\n`boolean`\n\nTo indicate whether the field has been touched/visited.\n\n### isDirty\n\n`boolean`\n\nTo indicate whether the field has been modified.\n\n## Example\n\nThe example demonstrates the basic usage of this hook.\n\n:::note\nWhen using the hook (and not working with [field-array](../getting-started/arrays-and-lists#dealing-with-array-fields)), a default value is required.\n:::\n\n```js\nimport { useControlled } from \"react-cool-form\";\n\nconst Field = ({\n  as,\n  name,\n  defaultValue,\n  validate,\n  parse,\n  format,\n  errorWithTouched,\n  ...restProps\n}) => {\n  const [fieldProps, { error, isTouched, isDirty }] = useControlled(name, {\n    defaultValue,\n    validate,\n    parse,\n    format,\n    errorWithTouched,\n    ...restProps,\n  });\n  const Component = as;\n\n  return <Component {...fieldProps} />;\n};\n```\n"
  },
  {
    "path": "docs/api-reference/use-field-array.md",
    "content": "---\nid: use-field-array\ntitle: useFieldArray\n---\n\nThis hook supplies you with functions for manipulating the array/list of fields, it's fast! See the [Arrays and Lists](../getting-started/arrays-and-lists) to learn more.\n\n```js\nconst [fields, helpers] = useFieldArray(name, config);\n```\n\n## Name\n\n`string`\n\nThe name of the field. We must provide it when using this hook.\n\n## Config\n\nAn `object` with the following options:\n\n### formId\n\n`string`\n\nThe [corresponding ID](./use-form#id) of the `useForm` hook. We only need it when using multiple form hooks at the same time.\n\n### defaultValue\n\n`string`\n\nThe default value of the field. Useful for dealing with the case of [conditional fields](../examples/conditional-fields).\n\n### validation\n\n`(value: any, values: FormValues) => any | Promise<any>`\n\nA synchronous/asynchronous function that is used for the [field-level validation](../getting-started/validation-guide#field-level-validation).\n\n## Fields\n\n`string[]`\n\nAn array that holds field names (e.g. `foo[0]`, `foo[1]`), which can be used for the `key` and `name` attributes of a field.\n\n- It refers to the location of the field in the [form state](../getting-started/form-state#about-the-form-state). If the referenced value isn't an `array` type, returns an empty array instead.\n- It doesn't include the field data. If you need to access the data, use the [use](./use-form#use) or [getState](./use-form#getstate) methods.\n\n```js\nconst [fields] = useFieldArray(\"foo\", { defaultValue: [{ name: \"Iron Man\" }] });\n\n// The first parameter of the callback supplies you a field name (e.g. foo[0], foo[1])\nfields.map((fieldName) => (\n  <input\n    key={fieldName} // Use the \"fieldName\" as the key\n    name={`${fieldName}.name`} // Use the \"fieldName\" + \"YOUR PATH\" as the name\n  />\n));\n```\n\n## Helpers\n\nAn `object` with the following methods:\n\n### push\n\n`(value: FieldValue, options?: Object) => void`\n\nAdd a value to the end of an array.\n\n```js\nconst handleAdd = () => {\n  push(\n    { name: \"Iron Man\" },\n    {\n      shouldTouched: false, // (Default = false) Set the field as touched\n      shouldDirty: true, // (Default = true) Set the field as dirty\n    }\n  );\n};\n```\n\n### insert\n\n`(index: number, value: FieldValue, options?: Object) => void`\n\nInsert an element at a given index into the array.\n\n```js\nconst handleInsert = () => {\n  insert(\n    0,\n    { name: \"Iron Man\" },\n    {\n      shouldTouched: false, // (Default = false) Set the field as touched\n      shouldDirty: true, // (Default = true) Set the field as dirty\n    }\n  );\n};\n```\n\n### swap\n\n`(indexA: number, indexB: number) => void`\n\nSwap two values in an array.\n\n### move\n\n`(from: number, to: number) => void`\n\nMove an element in an array to another index.\n\n### remove\n\n`(index: number) => FieldValue`\n\nRemove an element at an index of an array and return it.\n\n## Example\n\nThe example demonstrates the basic usage of this hook.\n\n```js\nimport { useForm, useFieldArray } from \"react-cool-form\";\n\nconst App = () => {\n  const { form } = useForm({\n    defaultValues: { foo: [{ name: \"Iron Man\" }] },\n  });\n  const [fields, { push, insert, move, swap, remove }] = useFieldArray(\"foo\");\n\n  return (\n    <form ref={form}>\n      {/* The first parameter of the callback supplies you a field name (e.g. foo[0], foo[1]) */}\n      {fields.map((fieldName) => (\n        <input\n          key={fieldName} // Use the \"fieldName\" as the key\n          name={`${fieldName}.name`} // Use the \"fieldName\" + \"YOUR PATH\" as the name\n        />\n      ))}\n    </form>\n  );\n};\n```\n"
  },
  {
    "path": "docs/api-reference/use-form-methods.md",
    "content": "---\nid: use-form-methods\ntitle: useFormMethods\n---\n\nThis hook allows us to use [all of the methods](./use-form#methods) provided by React Cool Form from a component at any level. See the [Do It Yourself](../getting-started/3rd-party-ui-libraries#3-do-it-yourself) to learn more.\n\n```js\nconst methods = useFormMethods(formId);\n```\n\n## formId\n\n`string`\n\nThe [corresponding ID](./use-form#id) of the `useForm` hook. We only need it when using multiple form hooks at the same time.\n\n## methods\n\nThe [methods](./use-form#methods) are the same as the `useForm` hook.\n\n## Example\n\nThe example demonstrates the basic usage of this hook.\n\n```js\nimport { useFormMethods } from \"react-cool-form\";\n\nconst Field = ({ as, name, onFocus, ...restProps }) => {\n  const { clearErrors, ...otherMethods } = useFormMethods();\n  const Component = as;\n\n  return (\n    <Component\n      name={name}\n      onFocus={(e) => {\n        clearErrors(name);\n        if (onFocus) onFocus(e);\n      }}\n      {...restProps}\n    />\n  );\n};\n```\n"
  },
  {
    "path": "docs/api-reference/use-form-state.md",
    "content": "---\nid: use-form-state\ntitle: useFormState\n---\n\nThis hook can be used for two purposes:\n\n- Isolating re-rendering: It helps us to isolate re-rendering at the component level for performance optimization (see [related article](https://overreacted.io/before-you-memo)). The API design similar to the [use](./use-form#use) method of the `useForm` that maintain a consistent DX for us. See the [Isolating Re-rendering](../getting-started/form-state#isolating-re-rendering) to learn more.\n- On state change event: To listen for changes to properties in the [form state](../getting-started/form-state#about-the-form-state) without triggering re-renders. See the [On State Change Event](../getting-started/form-state#on-state-change-event) to learn more.\n\n```js\n// Isolating re-rendering mode\nconst props = useFormState(path, config);\n\n// On state change event mode\nuseFormState(path, callback, formId);\n```\n\n## Path\n\n`string | string[] | Record<string, string>`\n\nThe path of the property we want to access from the [form state](../getting-started/form-state#about-the-form-state). We can construct the return values as follows.\n\n- Every time an accessed value changed that will trigger re-renders. Thus, there're [some guidelines](../getting-started/form-state#best-practices) for us to use the form state.\n- You can access the form's values without the `values.` prefix, ya! it's a shortcut for for your convenience.\n\n```js\n// Getting a value\nconst foo = useFormState(\"values.foo\");\n\n// Shortcut for getting a value\nconst foo = useFormState(\"foo\");\n\n// Array pick\nconst [foo, bar] = useFormState([\"values.foo\", \"values.bar\"]);\n\n// Object pick\nconst { foo, bar } = useFormState({ foo: \"values.foo\", bar: \"values.bar\" });\n```\n\n## Config\n\nAn `object` with the following options:\n\n### formId\n\n`string`\n\nThe [corresponding ID](./use-form#id) of the `useForm` hook. We only need it when using multiple form hooks at the same time.\n\n### defaultValues\n\n`FormValues`\n\nThe alternative default values for this hook to return when we didn't provide them via the [defaultValues option](./use-form#defaultvalues) of the `useForm`. Two common use cases of this option are as follows:\n\n- Setting a default value for a field via the `defaultValue` attribute.\n- Setting a default value for a field via the `useControlled`'s [defaultValue option](./use-controlled#defaultvalue).\n\n### errorWithTouched\n\n`boolean`\n\nEnable/disable the feature of **filtering untouched errors**, which can help the user focus on typing without being annoyed by the error message. Default is `false`.\n\n```js\n// Current state: { errors: { foo: \"Required\" }, touched: {} }\n// Returns { foo: \"Required\" }\nconst errors = useFormState(\"errors\");\n\n// Current state: { errors: { foo: \"Required\" }, touched: {} }\n// Returns {}\nconst errors = useFormState(\"errors\", { errorWithTouched: true );\n\n// Current state: { errors: { foo: \"Required\" }, touched: { foo: true } }\n// Returns { foo: \"Required\" }\nconst errors = useFormState(\"errors\", { errorWithTouched: true );\n```\n\n## Callback\n\n`(props: any) => void`\n\nIt's called on any of the subscribed properties in the [form state](../getting-started/form-state#about-the-form-state) change. It takes the properties as the parameter.\n\n## FormId\n\n`string`\n\nAn optional parameter that works the same as the [config.formId](#formid).\n\n## Example\n\nThe example demonstrates the basic usage of this hook.\n\n```js\nimport { useFormState } from \"react-cool-form\";\n\n// To isolate re-rendering at the component level\nconst IsolatedComponent = () => {\n  const foo = useFormState(\"foo\");\n\n  return <div>{foo}</div>;\n};\n\n// To listen for the changes of a field value\nuseFormState(\"foo\", (foo) => console.log(foo));\n```\n"
  },
  {
    "path": "docs/api-reference/use-form.md",
    "content": "---\nid: use-form\ntitle: useForm\n---\n\nThis is a custom React [hook](https://reactjs.org/docs/hooks-custom.html#using-a-custom-hook) that helps you with building forms. It takes `config` parameters and returns useful methods as follows.\n\n```js\nconst methods = useForm(config);\n```\n\n## Config\n\nAn `object` with the following options:\n\n### id\n\n`string`\n\nThe ID of the hook, it's used to pair with the related hook(s) of React Cool Form. We only need it when using multiple form hooks at the same time.\n\n### defaultValues\n\n`Record<string, any>`\n\nDefault field values of the form. In most case (especially working with TypeScript), we should use it to initialize a field's value and use the [defaultValue/defaultChecked](https://reactjs.org/docs/uncontrolled-components.html#default-values) attribute for the case of [conditional fields](../examples/conditional-fields). The `defaultValues` also used to compare against the current values to calculate `isDirty` and `dirty`.\n\n- The `defaultValues` is cached **at the first render** within the custom hook. If you want to reset it or [lazily set it](../examples/lazy-default-values), you can use the [reset](#reset) method.\n\n### excludeFields\n\n`string[]`\n\nTell React Cool Form to exclude field(s) by passing in the `name`/`id`/`class` of the field. You can also exclude a field via the pre-defined `data-rcf-exclude` attribute.\n\n- The `excludeFields` and `data-rcf-exclude` won't affect the functionality of the [useControlled](./use-controlled).\n\n```js {3,12}\nconst App = () => {\n  const { form } = useForm({\n    excludeFields: [\"foo\", \"#bar\", \".baz\"],\n  });\n\n  return (\n    <form ref={form}>\n      <input name=\"foo\" />\n      <input id=\"bar\" />\n      <input className=\"baz\" />\n      {/* Excluding via the pre-defined data attribute */}\n      <input data-rcf-exclude />\n    </form>\n  );\n};\n```\n\n👉🏻 See the [Exclude Fields](../getting-started/integration-an-existing-form#exclude-fields) to learn more.\n\n### builtInValidationMode\n\n`\"message\" | \"state\" | false`\n\nWe can configure the [mode of the built-in validation](../getting-started/validation-guide#displaying-error-messages) as follows:\n\n- `\"message\"` (default): Returns [a localized message](https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validationMessage) that describes the validation constraints that the field does not satisfy (if any)\n- `\"state\"`: Returns the **key of the invalid property** (e.g. \"valueMissing\", \"tooShort\", etc.) of the [ValidityState](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState) (if any)\n- `false`: Disable the [built-in validation](../getting-started/validation-guide#built-in-validation)\n\n### validateOnChange\n\n`boolean`\n\nTell React Cool Form to run validations on `change` events as well as the [setValue](#setvalue) method. Default is `true`.\n\n### validateOnBlur\n\n`boolean`\n\nTell React Cool Form to run validations on `blur` events. Default is `true`.\n\n### focusOnError\n\n`boolean | string[] | (names: string[]) => string[]`\n\nTell React Cool Form to apply focus to the first field with an error upon an attempted form submission. Default is `true`.\n\n- Only native input elements that support [HTMLElement.focus()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus) will work.\n- The focus order is based on the field order (i.e. top-to-bottom and left-to-right).\n\n```js\n// Current fields: { foo: \"\", bar: \"\", baz: \"\" }\n\n// Disable this feature\nconst methods = useForm({ focusOnError: false });\n\n// Change the focus order by passing in field names\nconst methods = useForm({ focusOnError: [\"bar\", \"foo\", \"baz\"] });\n\n// Change the focus order by modifying existing field names\nconst methods = useForm({\n  focusOnError: (names) => {\n    [names[0], names[1]] = [names[1], names[0]];\n    return names;\n  },\n});\n```\n\n### removeOnUnmounted\n\n`boolean | string[] | (names: string[]) => string[]`\n\nBy default, React Cool Form automatically removes the **related state** (i.e. value, error, touched, dirty) and **default value** of an unmounted field for us. However, we can set the `removeOnUnmounted` to `false` to maintain all the data or give it field names to maintain partial data. Default is `true`.\n\n- To keep a default value existing between a dynamically show/hide field, we can set it via `defaultValue` attribute or option.\n- If this feature doesn't meet your needs, you can use the [removeField](#removefield) to control what data that you want to remove instead.\n\n```js\n// Current values: { foo: \"🍎\", bar: \"🍋\", baz: \"🥝\" }\n\n// Keep all the data\nconst methods = useForm({ removeOnUnmounted: false });\n\n// Keep partial data (i.e. \"bar\" and \"baz\") by passing in field names\nconst methods = useForm({ removeOnUnmounted: [\"foo\"] });\n\n// Keep partial data (i.e. \"bar\" and \"baz\") by modifying existing field names\nconst methods = useForm({\n  removeOnUnmounted: (names) => names.filter((name) => name === \"foo\"),\n});\n```\n\n👉🏻 See the [conditional fields](../examples/conditional-fields) example to learn more.\n\n### validate\n\n`(values: FormValues) => FormErrors | false | void | Promise<FormErrors | false | void>`\n\nA synchronous/asynchronous function that is used for the [form-level validation](../getting-started/validation-guide#form-level-validation). It takes all the form's values and returns any validation errors (or returns `undefined` if there's no error). The validation errors must be in the same shape as the values of the form.\n\n### onSubmit\n\n`(values: FormValues, options: Object, e?: Event) => void | Promise<void>`\n\nThe form submission handler will be called when the form is submitted (or when the [submit](#submit) method is called) and validated successfully. It takes the following parameters:\n\n```js\nconst methods = useForm({\n  onSubmit: async (\n    values,\n    {\n      getState,\n      setValue,\n      setTouched,\n      setDirty,\n      setError,\n      focus,\n      runValidation,\n      removeField,\n      submit,\n      reset,\n    },\n    e\n  ) => {\n    /* Do something... */\n  },\n});\n```\n\n👉🏻 See the [Form Submission](../getting-started/form-submission) to learn more.\n\n### onError\n\n`(errors: FormErrors, options: Object, e?: Event) => void`\n\nThe form error handler that is called when the form is submitted (or when the [submit](#submit) method is called) and validated failed. It takes the following parameters:\n\n```js\nconst methods = useForm({\n  onError: (\n    errors,\n    {\n      getState,\n      setValue,\n      setTouched,\n      setDirty,\n      setError,\n      focus,\n      runValidation,\n      removeField,\n      submit,\n      reset,\n    },\n    e\n  ) => {\n    /* Do something... */\n  },\n});\n```\n\n👉🏻 See the [Form Submission](../getting-started/form-submission) to learn more.\n\n### onReset\n\n`(values: FormValues, options: Object, e?: Event) => void`\n\nThe form reset handler that is called when the form is reset (or when the [reset](#reset) method is called). It takes the following parameters:\n\n```js\nconst methods = useForm({\n  onReset: (\n    values,\n    {\n      getState,\n      setValue,\n      setTouched,\n      setDirty,\n      setError,\n      focus,\n      runValidation,\n      removeField,\n      submit,\n      reset,\n    },\n    e\n  ) => {\n    /* Do something... */\n  },\n});\n```\n\n👉🏻 See the [Reset Form](../getting-started/reset-form) to learn more.\n\n### onStateChange\n\n`(formState: FormState) => void`\n\nThe form state change handler that is called on every state change. It's useful for **debugging** or **triggering a handler**.\n\n- Want to trigger a handler based on certain properties in the form state? Check out the [useFormState](./use-form-state) to learn more.\n- `formState` is readonly and should not be mutated directly.\n\n```js\nconst methods = useForm({\n  onStateChange: (formState) => console.log(\"State: \", formState),\n});\n```\n\n## Methods\n\nAn `object` with the following methods:\n\n### form\n\n`(element: HTMLElement) => void`\n\nThis method allows us to integrate [an existing form](../getting-started/integration-an-existing-form#hook-into-a-form) or [a container where inputs are used](../getting-started/integration-an-existing-form#without-using-a-form-element) with React Cool Form.\n\n### field\n\n`(validateOrOptions: Function | Object) => Function`\n\nThis method allows us to do [field-level validation](../getting-started/validation-guide#field-level-validation) and data type conversion via the `ref` attribute. For the data type conversion, React Cool Form supports the [valueAsNumber](https://www.w3.org/TR/2011/WD-html5-20110405/common-input-element-attributes.html#dom-input-valueasnumber), [valueAsDate](https://www.w3.org/TR/2011/WD-html5-20110405/common-input-element-attributes.html#dom-input-valueasdate), and custom parser.\n\n- For your convenience, the values of `<input type=\"number\">` and `<input type=\"radio\">` are converted to `number` by default.\n- When using this method with the [useControlled](./use-controlled), the functionality of the method will be replaced.\n\n```js\nconst { field } = useForm();\n\n<input\n  name=\"foo\"\n  type=\"date\"\n  ref={field({\n    validate: (value, values /* Form values */) => !value.length && \"Required\",\n    valueAsNumber: true, // (Default = false) Returns a number representing the field's value if applicable, otherwise, returns \"NaN\"\n    valueAsDate: true, // (Default = false) Returns a Date object representing the field's value if applicable, otherwise, returns \"null\"\n    parse: (value) => customParser(value), // Returns whatever value you want through the callback\n  })}\n/>;\n```\n\nIf you just want to validate the field, there's a shortcut for it:\n\n```js\n<input nam=\"foo\" ref={field((value) => !value.length && \"Required\")} />\n```\n\n### focus\n\n`(name: string, delay?: number) => void`\n\nThis method allows us to apply focus to a field. If you want to focus on the first field of a nested fields, you can just pass in the parent path as below.\n\n:::note\nWhen working with [Arrays and Lists](../getting-started/arrays-and-lists), we need to set `delay` (delay = 0 is acceptable) to wait for a field rendered before applying focus to it.\n:::\n\n```js {7,12}\nconst App = () => {\n  const { form, focus } = useForm();\n\n  useEffect(() => {\n    // Will focuses on the first field after 0.5 second\n    // It works the same as `focus(\"foo.a\", 500)`\n    focus(\"foo\", 500);\n  }, []);\n\n  return (\n    <form ref={form}>\n      <input name=\"foo.a\" />\n      <input name=\"foo.b\" />\n      <input name=\"foo.c\" />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n👉🏻 See the [Applying Focus](../getting-started/arrays-and-lists#applying-focus) to learn more.\n\n### use\n\n`(path: string | string[] | Record<string, string>, options?: Object) => any`\n\nThis method provides us a performant way to use the form state with minimized re-renders. See the [Form State](../getting-started/form-state) to learn more.\n\n### getState\n\n`(path?: string | string[] | Record<string, string>) => any`\n\nThis method allows us to read the form state without triggering re-renders. See the [Reading the State](../getting-started/form-state#reading-the-state) to learn more.\n\n### setValue\n\n`(name: string, value: any | Function, options?: Object) => void`\n\nThis method allows us to manually set/clear the value of a field. Useful for creating custom field change handlers.\n\n```js\nconst { setValue } = useForm();\n\nsetValue(\"fieldName\", \"value\", {\n  shouldValidate: true, // (Default = \"validateOnChange\" option) Triggers field validation\n  shouldTouched: true, // (Default = true) Sets the field as touched\n  shouldDirty: true, // (Default = true) Sets the field as dirty\n});\n\n// We can also pass a callback as the \"value\" parameter, similar to React's setState callback style\nsetValue(\"fieldName\", (prevValue) => prevValue.splice(2, 0, \"🍎\"));\n```\n\nWe can clear the value of a field by the following way:\n\n```js\nsetValue(\"fieldName\", undefined); // The field will be unset: { fieldName: \"value\" } → {}\n```\n\n### setTouched\n\n`(name: string, isTouched?: boolean, options?: Object) => void`\n\nThis method allows us to manually set/clear the touched of a field. Useful for creating custom field touched handlers.\n\n```js\nconst { setTouched } = useForm();\n\n// Common use case\nsetTouched(\"fieldName\");\n\n// Full parameters\nsetTouched(\n  \"fieldName\",\n  true, // (Default = true) Sets the field as touched\n  {\n    shouldValidate: true, // (Default = \"validateOnBlur\" option) Triggers field validation\n  }\n);\n```\n\nWe can clear the touched of a field by the following way:\n\n```js\nsetTouched(\"fieldName\", false); // The touched will be unset: { fieldName: true } → {}\n```\n\n### setDirty\n\n`(name: string, isDirty?: boolean) => void`\n\nThis method allows us to manually set/clear the dirty of a field. Useful for creating custom field dirty handlers.\n\n```js\nconst { setDirty } = useForm();\n\n// Common use case\nsetDirty(\"fieldName\");\n```\n\nWe can clear the dirty of a field by the following way:\n\n```js\nsetDirty(\"fieldName\", false); // The dirty will be unset: { fieldName: true } → {}\n```\n\n### setError\n\n`(name: string, error: any | Function) => void`\n\nThis method allows us to manually set/clear the error of a field. Useful for creating custom field error handlers.\n\n```js\nconst { setError } = useForm();\n\nsetError(\"fieldName\", \"Required\");\n\n// We can also pass a callback as the \"error\" parameter, similar to React's setState callback style\nsetError(\"fieldName\", (prevError) => (prevError ? \"Too short\" : \"Required\"));\n```\n\nWe can clear the error of a field by the following way (or using [clearErrors](#clearerrors)):\n\n```js\nsetError(\"fieldName\", undefined); // Or any falsy values, the error will be unset: { fieldName: \"Required\" } → {}\n```\n\n### clearErrors\n\n`(name?: string | string[]) => void`\n\nThis method allows us to manually clear errors (or an error). Useful for creating custom field error handlers.\n\n```js\nconst { clearErrors } = useForm();\n\n// Current errors: { foo: { bar: \"Required\", baz: \"Required\" }, qux: \"Required\" }\n\nclearErrors(); // Clears all errors. Result: {}\n\nclearErrors(\"foo\"); // Clears both \"foo.bar\" and \"foo.baz\". Result: { qux: \"Required\" }\n\nclearErrors([\"foo.bar\", \"foo.baz\"]); // Clears \"foo.bar\" and \"foo.baz\" respectively. Result: { foo: {}, qux: \"Required\" }\n```\n\n### runValidation\n\n`(name?: string | string[], options?: Object) => Promise<boolean>`\n\nThis method allows us to manually run validation for the form or field(s).\n\n- It returns a `boolean` that indicates the validation results, `true` means valid, `false` otherwise.\n- Please note, when enabling the [Filter Untouched Field Errors](../getting-started/form-state#filter-untouched-field-errors), only the errors of the touched fields are accessible.\n\n```js\nconst { runValidation } = useForm();\n\n// Validates the form (i.e. all the fields)\nrunValidation();\n\n// Validates single field\nrunValidation(\"fieldName\");\n\n// Validates multiple fields\nrunValidation([\"fieldName1\", \"fieldName2\"]);\n\n// With result\nconst validateForm = async () => {\n  const isValid = await runValidation();\n  console.log(\"The form is: \", isValid ? \"valid\" : \"invalid\");\n};\n\n// Full parameters\nrunValidation(\"fieldName\", {\n  shouldFocus: true, // (Default = \"focusOnError\" option) To focus to the first field with an error within the specified fields\n});\n```\n\n👉🏻 See the [Validation Guide](../getting-started/validation-guide) to learn more.\n\n### removeField\n\n`(name: string, exclude?: string[]) => void`\n\nThis method allows us to manually remove the **related state** (i.e. value, error, touched, dirty) and **default value** of a field, it also excludes a field from the form.\n\n- By default, React Cool Form automatically [removes an unmounted field](#removeonunmounted) for us but this method gives us the ability to control what data that we want to remove.\n\n```js {4,10}\nconst App = () => {\n  const [show, setShow] = useState(true);\n  const { form, removeField } = useForm({\n    removeOnUnmounted: false, // Disable the feature of automatically removing fields\n  });\n\n  const handleToggle = () => {\n    setShow(!show);\n    // We can exclude these data: [\"defaultValue\", \"value\", \"error\", \"touched\", \"dirty\"]\n    if (!show) removeField(\"foo\", [\"defaultValue\"]); // Keep the default value\n  };\n\n  return (\n    <form ref={form}>\n      <input type=\"checkbox\" onChange={handleToggle} data-rcf-exclude />\n      {show && <input name=\"foo\" />}\n      {/* Other fields... */}\n    </form>\n  );\n};\n```\n\n### submit\n\n`(e?: Event) => Promise<Result>`\n\nThis method allows us to manually submit the form, it returns a promise with the following results. Useful for meeting the needs of custom design.\n\n- Returns a promise with `errors` when any validation errors\n- Returns a promise with `values` when the form is validated successfully\n\n```js\nconst { submit } = useForm({\n  onSubmit: (values, options, e) => console.log(\"onSubmit: \", values), // Triggered on form submit + valid\n  onError: (errors, options, e) => console.log(\"onError: \", errors), // Triggered on form submit + invalid\n});\n\nconst handleFormSubmit = async (e) => {\n  const { errors, values } = await submit(e); // Pass the event object to the event handlers\n\n  if (errors) {\n    // Do something for invalid case\n  } else {\n    // Do something for valid case\n  }\n};\n```\n\n👉🏻 See the [Form Submission](../getting-started/form-submission) to learn more.\n\n### reset\n\n`(values?: FormValues | Function | null, exclude?: string[] | null, e?: Event) => void`\n\nThis method allows us to manually reset the form. It will restore the form to its default values as well as reset/clear all the [related state](../getting-started/form-state#about-the-form-state).\n\n- We can pass `values` as an optional parameter to update the default values.\n- We can pass `exclude` as an optional parameter to prevent specific [state](../getting-started/form-state#about-the-form-state) from reset.\n\n```js\nconst { reset } = useForm({\n  defaultValues: { firstName: \"\", lastName: \"\" },\n  onReset: (values, options, e) => console.log(\"onReset: \", values), // Triggered on form reset\n});\n\nconst handleFormReset = (e) => {\n  reset(\n    { firstName: \"Welly\", lastName: \"Shen\" }, // Update the default values\n    [\"isSubmitted\", \"submitCount\"], // Don't reset the \"isSubmitted\" and \"submitCount\" state\n    e // Pass the event object to the \"onReset\" handler\n  );\n\n  // We can also pass a callback as the \"values\" parameter, similar to React's setState callback style\n  reset((prevValues) => ({ ...prevValues, firstName: \"Bella\" }));\n};\n```\n\n👉🏻 See the [Reset Form](../getting-started/reset-form) to learn more.\n"
  },
  {
    "path": "docs/api-reference/utility-functions.md",
    "content": "---\nid: utility-functions\ntitle: Utility Functions\n---\n\nReact Cool Form exports useful utility functions that can help you handle [complex structures](../getting-started/complex-structures) efficiently.\n\n```js\nimport { get, set, unset } from \"react-cool-form\";\n```\n\n## get\n\n`(object: Record<string, any>, path: string, defaultValue?: unknown) => any`\n\nGets the value at path of object. If the resolved value is `undefined`, the `defaultValue` is returned in its place.\n\n```js {8}\nimport { useForm, get } from \"react-cool-form\";\n\nconst { form } = useForm({\n  defaultValues: { foo: { bar: { baz: \"\" } } },\n  validate: (values) => {\n    const errors = {};\n\n    if (!get(values, \"foo.bar.baz\", \"\")) errors.foo.bar.baz = \"Required\";\n\n    return errors;\n  },\n\n  // ...\n});\n```\n\n## set\n\n`(object: Record<string, any>, path: string, value: unknown, immutable?: boolean) => any`\n\nSets the value at `path` of `object`. If a portion of `path` doesn't exist, it's created. Arrays are created for missing index properties while objects are created for all other missing properties.\n\n```js {10,12}\nimport { useForm, set } from \"react-cool-form\";\n\nconst { form } = useForm({\n  defaultValues: { foo: { bar: { baz: \"\" } } },\n  validate: (values) => {\n    const errors = {};\n\n    if (!values.foo.bar.baz) {\n      // Mutable way\n      set(errors, \"foo.bar.baz\", \"Required\");\n      // Immutable way\n      errors = set(errors, \"foo.bar.baz\", \"Required\", true);\n    }\n\n    return errors;\n  },\n\n  // ...\n});\n```\n\n## unset\n\n`(object: Record<string, any>, path: string, immutable?: boolean) => any`\n\nRemoves the property at `path` of `object`.\n\n- If the property remains empty, the parent properties will be removed as well.\n- It will clear the redundant `empty` or `undefined` element(s) of an array.\n\n```js {12,14}\nimport { useForm, unset } from \"react-cool-form\";\n\nconst { form } = useForm({\n  defaultValues: { foo: { bar: { baz: \"\" } } },\n  validate: (values) => {\n    const errors = {};\n\n    if (!values.foo.bar.baz) {\n      // ...\n    } else {\n      // Mutable way\n      unset(errors, \"foo.bar.baz\");\n      // Immutable way\n      errors = unset(errors, \"foo.bar.baz\", true);\n    }\n\n    return errors;\n  },\n\n  // ...\n});\n```\n"
  },
  {
    "path": "docs/examples/arrays-and-lists.md",
    "content": "---\nid: arrays-and-lists\ntitle: Arrays and Lists\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to work with array fields in React Cool Form.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-arrays-and-lists-crv9d?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Arrays and Lists\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/basic.md",
    "content": "---\nid: basic\ntitle: Basic\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to use form inputs (input, select, and textarea) to build a form with no validation.\n\n<iframe src=\"https://codesandbox.io/embed/happy-paper-17fz0?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Basic\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/built-in-validation.md",
    "content": "---\nid: built-in-validation\ntitle: Built-in Validation\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to use [HTML form validation](https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation#Using_built-in_form_validation) to validate a form.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-built-in-validation-1h28u?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Built-in Validation\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/checkboxes.md",
    "content": "---\nid: checkboxes\ntitle: Checkboxes\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to use React Cool Form with a checkbox group and how to validate it. Given that fields all the share `name` and the respective `value`, React Cool Form will automatically bind them into a single array.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-checkboxes-z80f3?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Checkboxes\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/complex-strcutures.md",
    "content": "---\nid: complex-structures\ntitle: Complex Structures\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to handle [Complex Structures](../getting-started/complex-structures) in React Cool Form.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-complex-structures-4x4n1?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Complex Structures\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/conditional-fields.md",
    "content": "---\nid: conditional-fields\ntitle: Conditional Fields\nhide_table_of_contents: true\n---\n\nBy default, when a form input element ([input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input), [select](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select), and [textarea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)) is unmounted, React Cool Form will auto remove it for us. Useful for dealing with conditional fields, let's take a look at the following example:\n\n<iframe src=\"https://codesandbox.io/embed/rcf-conditional-fields-rnxe6?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Conditional Fields\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/custom-field.md",
    "content": "---\nid: custom-field\ntitle: Custom Field\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to combine the [useFormState](../api-reference/use-form-state) and [useFormMethods](../api-reference/use-form-methods) to DIY a custom field.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-custom-field-p9lqi?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Custom Field\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/field-level-validation.md",
    "content": "---\nid: field-level-validation\ntitle: Field-level Validation\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to validate a form by the [field](../api-reference/use-form#field) method of React Cool Form.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-field-level-validation-dbklg?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Field-level Validation\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/form-level-validation.md",
    "content": "---\nid: form-level-validation\ntitle: Form-level Validation\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to validate a form by the [validate](../api-reference/use-form#validate) option of React Cool Form.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-form-level-validation-2if7r?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Form-level Validation\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/form-submission.md",
    "content": "---\nid: form-submission\ntitle: Form Submission\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to submit a form in React Cool Form.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-form-submission-qixkl?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Form Submission\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/isolating-rerendering.md",
    "content": "---\nid: isolating-rerendering\ntitle: Isolating Re-rendering\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to isolate re-rendering at the component level via the [useFormState](../api-reference/use-form-state) hook.\n\n<iframe src=\"https://codesandbox.io/embed/intelligent-banach-uqxyx?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Isolating Re-rendering\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/lazy-default-values.md",
    "content": "---\nid: lazy-default-values\ntitle: Lazy Default Values\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to set [defaultValues](../api-reference/use-form#defaultvalues) lazily.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-lazy-default-values-qxvlz?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Lazy Default Values\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/material-ui.md",
    "content": "---\nid: material-ui\ntitle: Material-UI\nhide_table_of_contents: true\n---\n\nThis example demonstrates the easiest way to integrate [Material-UI](https://material-ui.com) with your form that you have never seen 😎.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-material-ui-xyi0b?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Material-UI\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/multi-select.md",
    "content": "---\nid: multi-select\ntitle: Multi-select\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to use React Cool Form with a multi-select input. Given the select element a `multiple` attribute. React Cool Form will automatically bind the options into a single array.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-multi-select-z2q29?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Multi-select\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/radio-group.md",
    "content": "---\nid: radio-group\ntitle: Radio Group\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to use React Cool Form with a radio group.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-radio-group-xbbvj?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Radio Group\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/react-select.md",
    "content": "---\nid: react-select\ntitle: React Select\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to use React Cool Form's [useControlled](../api-reference/use-controlled) hook to integrate [React Select](https://react-select.com) with your form.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-react-select-djsl1?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - React Select\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/reset-form.md",
    "content": "---\nid: reset-form\ntitle: Reset Form\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to reset a form in React Cool Form.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-reset-form-uikxg?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Reset Form\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/validation-with-schema.md",
    "content": "---\nid: validation-with-schema\ntitle: Validation with Schema\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to validate a form with a 3rd-party (e.g. [Yup](https://github.com/jquense/yup) or [Joi](https://github.com/sideway/joi)).\n\n<iframe src=\"https://codesandbox.io/embed/rcf-schema-lsk6f?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Schema\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/virtualized-lists.md",
    "content": "---\nid: virtualized-lists\ntitle: Virtualized Lists\nhide_table_of_contents: true\n---\n\nWhen working with millions of list items, I'd like to recommend using [React Cool Virtual](https://github.com/wellyshen/react-cool-virtual) to virtualized the list for better performance. It works nicely with React Cool Form, let's dive into it.\n\n<iframe src=\"https://codesandbox.io/embed/rcv-rcf-y6wiq?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCV - RCF\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/without-form-element.md",
    "content": "---\nid: without-form-element\ntitle: Without <form> Element\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to integrate React Cool Form without using a `<form>` element.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-without-form-element-wvctm?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Without Form Element\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/examples/wizard-form.md",
    "content": "---\nid: wizard-form\ntitle: Wizard Form\nhide_table_of_contents: true\n---\n\nThis example demonstrates how to integrate React Cool Form with [React Router](https://github.com/ReactTraining/react-router) to create a multi-step route-based form (a.k.a wizard form), with validation for each step.\n\n<iframe src=\"https://codesandbox.io/embed/rcf-wizard-form-cd3qc?fontsize=14&hidenavigation=1&theme=dark\"\n  style={{ width: \"100%\", height: \"500px\", border: \"0\", borderRadius: \"4px\",  overflow: \"hidden\" }}\n  title=\"RCF - Wizard Form\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n></iframe>\n"
  },
  {
    "path": "docs/getting-started/3rd-party-ui-libraries.md",
    "content": "---\nid: 3rd-party-ui-libraries\ntitle: 3rd-Party UI Libraries\n---\n\nLife is hard but coding can be easier. The reason we ❤️ open-source software (OSS) is because there're many awesome libraries that help us making a better world by software products. React Cool Form bears the faith in mind, it allows us integrate with any 3rd-party UI libraries easily. There're three ways to integrate with an UI library in React Cool Form.\n\n## 1. Seamless Integration\n\n[Uncontrolled components](https://reactjs.org/docs/uncontrolled-components.html) or components that rely on native input elements (i.e. [input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input), [select](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select), and [textarea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)) to work under the hood, we need to do nothing 😂. For example: [Material-UI](https://material-ui.com)'s [TextField](https://material-ui.com/components/text-fields), [Checkbox](https://material-ui.com/components/checkboxes), and [Select](https://material-ui.com/components/selects), etc.\n\n[![Edit RCF - Material-UI](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-material-ui-xyi0b?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm } from \"react-cool-form\";\nimport {\n  FormControl,\n  FormControlLabel,\n  FormLabel,\n  InputLabel,\n  TextField,\n  Select,\n  Checkbox,\n  Button,\n} from \"@material-ui/core\";\n\nconst App = () => {\n  const { form, use } = useForm({\n    defaultValues: { username: \"\", framework: \"\", fruit: [] },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  const errors = use(\"errors\");\n\n  return (\n    <form ref={form} noValidate>\n      <TextField\n        label=\"Username\"\n        name=\"username\"\n        required\n        error={!!errors.username}\n        helperText={errors.username}\n      />\n      <FormControl>\n        <InputLabel htmlFor=\"framework\">Framework</InputLabel>\n        {/* When working with select, we need to enable the native select element or you can use the \"NativeSelect\" instead */}\n        <Select inputProps={{ id: \"framework\", name: \"framework\" }} native>\n          <option aria-label=\"None\" value=\"I'm interesting in...\" />\n          <option value=\"react\">React</option>\n          <option value=\"vue\">Vue</option>\n          <option value=\"angular\">Angular</option>\n          <option value=\"svelte\">Svelte</option>\n        </Select>\n      </FormControl>\n      <FormControl component=\"fieldset\"></FormControl>\n      <div>\n        <FormLabel component=\"legend\">Fruit</FormLabel>\n        <FormControlLabel\n          control={<Checkbox />}\n          name=\"fruit\"\n          value=\"🍎\"\n          label=\"🍎\"\n        />\n        <FormControlLabel\n          control={<Checkbox />}\n          name=\"fruit\"\n          value=\"🍋\"\n          label=\"🍋\"\n        />\n        <FormControlLabel\n          control={<Checkbox />}\n          name=\"fruit\"\n          value=\"🥝\"\n          label=\"🥝\"\n        />\n      </div>\n      <Button type=\"submit\" variant=\"contained\" color=\"primary\">\n        Submit\n      </Button>\n    </form>\n  );\n};\n```\n\n## 2. [useControlled Hook](../api-reference/use-controlled)\n\n[Controlled components](https://reactjs.org/docs/forms.html#controlled-components) with highly customized and full features like [React Select](https://react-select.com) or [React Datepicker](https://reactdatepicker.com). We can use React Cool Form's [useControlled](../api-reference/use-controlled) hook to create a reusable controller component for them in a flexible and performant way.\n\n:::note\nWhen using the hook (and not working with [field-array](./arrays-and-lists#dealing-with-array-fields)), a default value is required.\n:::\n\n[![Edit RCF - React Select](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-react-select-djsl1?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm, useControlled } from \"react-cool-form\";\nimport Select from \"react-select\";\n\nconst Field = ({ as, name, ...restProps }) => {\n  const [fieldProps] = useControlled(name, restProps);\n  const Component = as;\n\n  return <Component {...fieldProps} />;\n};\n\nconst options = [\n  { label: \"React\", value: \"react\" },\n  { label: \"Vue\", value: \"vue\" },\n  { label: \"Angular\", value: \"angular\" },\n  { label: \"Svelte\", value: \"svelte\" },\n];\n\nconst App = () => {\n  const { form } = useForm({\n    defaultValues: { framework: \"\" }, // We must provide a default value for the controlled field\n    excludeFields: [\"#framework\"], // Exclude the internal input element of React-Select by ID\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n\n  return (\n    <form ref={form}>\n      <Field\n        as={Select}\n        name=\"framework\"\n        inputId=\"framework\" // Used for excluding the internal input element of React-Select\n        options={options}\n        parse={(option) => option.value}\n        format={(value) => options.find((option) => option.value === value)}\n      />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## 3. Do It Yourself\n\nIf the above solutions can't meet your needs then you can set up a custom field with the [API](../api-reference/use-form#methods) of React Cool Form. The following example demonstrates how to combine the [useFormState](../api-reference/use-form-state) and [useFormMethods](../api-reference/use-form-methods) to DIY a custom field with full validation UX.\n\n[![Edit RCF - Custom Field](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-custom-field-p9lqi?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm, useFormState, useFormMethods } from \"react-cool-form\";\nimport { TextField, Button } from \"@material-ui/core\";\n\nconst Field = ({ as, name, onChange, onBlur, ...restProps }) => {\n  const value = useFormState(`values.${name}`);\n  const { setValue, setTouched } = useFormMethods();\n  const Component = as;\n\n  return (\n    <Component\n      name={name}\n      value={value}\n      onChange={(e) => {\n        setValue(name, e.target.value); // Update the field's value and set it as touched\n        if (onChange) onChange(e);\n      }}\n      onBlur={(e) => {\n        setTouched(name); // Set the field as touched for displaying error (if it's not touched)\n        if (onBlur) onBlur(e);\n      }}\n      {...restProps}\n    />\n  );\n};\n\nconst App = () => {\n  const { form, use } = useForm({\n    defaultValues: { username: \"\" },\n    // excludeFields: [\"username\"], // You can also exclude the field here\n    validate: ({ username }) => {\n      const errors = {};\n      if (!username.length) errors.username = \"Required\";\n      return errors;\n    },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  const errors = use(\"errors\");\n\n  return (\n    <form ref={form} noValidate>\n      <Field\n        as={TextField}\n        label=\"Username\"\n        name=\"username\" // Used for the \"excludeFields\" option\n        required\n        error={!!errors.username}\n        helperText={errors.username}\n        inputProps={{ \"data-rcf-exclude\": true }} // Exclude the field via the pre-defined data attribute\n      />\n      <Button type=\"submit\" variant=\"contained\" color=\"primary\">\n        Submit\n      </Button>\n    </form>\n  );\n};\n```\n"
  },
  {
    "path": "docs/getting-started/accessibility.md",
    "content": "---\nid: accessibility\ntitle: Accessibility (a11y)\nhide_table_of_contents: true\n---\n\nWeb accessibility (a.k.a [a11y](https://en.wiktionary.org/wiki/a11y)) is the design and creation of websites that can be used by everyone. Accessibility support is necessary to allow assistive technology to interpret web pages. React Cool Form is designed to keep your input elements **clean** that helps you build accessible forms by using standard HTML techniques.\n\n- Provide [`<label>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label) elements to all the form controls, a screen reader will read out the label when the user is focused on the field.\n- Use the [aria-invalid](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-invalid_attribute) to indicate a field has failed validation for the screen reader user.\n- Use the [aria-describedby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-describedby_attribute) to tie an error message with a field, a screen reader will read out the error message when the user is focused on the field.\n- Use the [alert role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_alert_role) to provide a suggestion to the user for correction on form field errors, a screen reader will read out the alert message when it's added to the document structure.\n\n```js\nimport { useForm } from \"react-cool-form\";\n\nconst App = () => {\n  const { form, use } = useForm({\n    defaultValues: { username: \"\", email: \"\", password: \"\" },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  const [errors, isValid] = use([\"errors\", \"isValid\"], {\n    errorWithTouched: true,\n  });\n\n  return (\n    <>\n      {!isValid && (\n        <h2>\n          <span role=\"alert\">\n            😭 Please fix the errors before you can submit this form\n          </span>\n        </h2>\n      )}\n      <form ref={form} noValidate>\n        <label htmlFor=\"username\">\n          Username <span>*</span>\n        </label>\n        <input\n          id=\"username\"\n          name=\"username\"\n          type=\"text\"\n          required\n          aria-invalid={!!errors.username}\n          aria-describedby=\"username-hint\"\n        />\n        {errors.username && <span id=\"username-hint\">{errors.username}</span>}\n        <label htmlFor=\"email\">\n          Email <span>*</span>\n        </label>\n        <input\n          id=\"email\"\n          name=\"email\"\n          type=\"email\"\n          required\n          aria-invalid={!!errors.email}\n          aria-describedby=\"email-hint\"\n        />\n        {errors.email && <span id=\"email-hint\">{errors.email}</span>}\n        <label htmlFor=\"password\">\n          Password <span>*</span>\n        </label>\n        <input\n          id=\"password\"\n          name=\"password\"\n          type=\"password\"\n          required\n          minLength={8}\n          aria-invalid={!!errors.password}\n          aria-describedby=\"password-hint\"\n        />\n        {errors.password && <span id=\"password-hint\">{errors.password}</span>}\n        <input type=\"submit\" />\n      </form>\n    </>\n  );\n};\n```\n"
  },
  {
    "path": "docs/getting-started/arrays-and-lists.md",
    "content": "---\nid: arrays-and-lists\ntitle: Arrays and Lists\n---\n\nThere can be situations in which the user needs to add or remove fields from a form depends on the amount of fields they need to fill out. Using React Cool Form, we can use the [useFieldArray](../api-reference/use-field-array) hook to easily deal with this situation.\n\n## Dealing with Array Fields\n\nThe `useFieldArray` hook helps you to deal with multiple similar fields. You pass it a `name` parameter with the path of the field that holds the relevant array. The hook will then give you the power to render an array of inputs as well as common array/list manipulations.\n\n:::note\nThe returned `fields` is an array of names. If you need to access the field's data, use the [use](../api-reference/use-form#use) or [getState](../api-reference/use-form#getstate) methods.\n:::\n\n[![Edit RCF - Arrays and Lists](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-arrays-and-lists-crv9d?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm, useFieldArray } from \"react-cool-form\";\n\nconst TextField = ({ name, ...restProps }) => {\n  const [fieldProps] = useControlled(name, restProps);\n  return <input {...fieldProps} />;\n};\n\nconst App = () => {\n  const { form } = useForm({\n    defaultValues: {\n      foo: [{ name: \"Iron Man\" }, { name: \"Hulk\" }],\n    },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  const [fields, { push, insert, move, swap, remove }] = useFieldArray(\"foo\");\n\n  return (\n    <form ref={form}>\n      {/* The first parameter of the callback supplies you a field name (e.g. foo[0], foo[1]) */}\n      {fields.map((fieldName, index) => (\n        // Use the \"fieldName\" as the key\n        <div key={fieldName}>\n          {/* Use the \"fieldName\" + \"YOUR PATH\" as the name */}\n          <input name={`${fieldName}.name`} />\n          {/* Working with a controlled component */}\n          <TextField name={`${fieldName}.name`} />\n          <button type=\"button\" onClick={() => remove(index)}>\n            ➖\n          </button>\n        </div>\n      ))}\n      <button type=\"button\" onClick={() => push({ name: \"Thor\" })}>\n        ➕\n      </button>\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## Applying Focus\n\nWhen dealing with dynamic list fields we can apply focus to a new field by the [focus](../api-reference/use-form#focus) method to provide better for the user.\n\n:::tip\nWhen working with nested fields, we can just pass in the parent path to the `focus` method. It will apply the focus to the first field.\n:::\n\n```js {28,30}\nimport { useForm, useFieldArray } from \"react-cool-form\";\n\nconst App = () => {\n  const { form, focus } = useForm({\n    defaultValues: {\n      foo: [{ name: \"Iron Man\", quote: \"I'm Iron Man\" }],\n    },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  const [fields, { push, remove }] = useFieldArray(\"foo\");\n\n  return (\n    <form ref={form}>\n      {fields.map((fieldName, index) => (\n        <div key={fieldName}>\n          <input name={`${fieldName}.name`} />\n          <input name={`${fieldName}.quote`} />\n          <button type=\"button\" onClick={() => remove(index)}>\n            ➖\n          </button>\n        </div>\n      ))}\n      <button\n        type=\"button\"\n        onClick={() => {\n          push({ name: \"Thor\", quote: \"I Knew It\" });\n          // We need to wait for the item rendered (delay = 0 is acceptable) then apply focus to the first field\n          focus(`foo[${fields.length}]`, 300);\n          // You can also apply focus to a specified field\n          focus(`foo[${fields.length}].quote`, 300);\n        }}\n      >\n        ➕\n      </button>\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## Conditional Fields\n\nThe `useFieldArray` hook also supports you to work with conditional fields.\n\n```js\nimport { useState } from \"react\";\nimport { useForm, useFieldArray } from \"react-cool-form\";\n\nconst TextField = ({ name, ...restProps }) => {\n  const [fieldProps] = useControlled(name, restProps);\n  return <input {...fieldProps} />;\n};\n\nconst App = () => {\n  const [toggle, setToggle] = useState(false);\n  const { form } = useForm({\n    defaultValues: { foo: [{ name: \"Iron Man\" }] },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  const [fields] = useFieldArray(\"foo\");\n\n  return (\n    <form ref={form}>\n      {fields.map((fieldName) => (\n        <div key={fieldName}>\n          <input name={`${fieldName}.name`} />\n          {toggle && (\n            <input\n              name={`${fieldName}.quote`}\n              defaultValue=\"I'm Iron Man\" // Provide the default value\n            />\n          )}\n          <TextField name={`${fieldName}.name`} />\n          {toggle && (\n            <TextField\n              name={`${fieldName}.quote`}\n              defaultValue=\"I'm Iron Man\" // Provide the default value\n            />\n          )}\n        </div>\n      ))}\n      <button type=\"button\" onClick={() => setToggle(!toggle)}>\n        Toggle\n      </button>\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## Top-level Field Validation\n\nYou can validate the top-level field via the [Form-level Validation](./validation-guide#form-level-validation) or [Field-level Validation](./validation-guide#field-level-validation) (via the `validate` option), depending on your case. React Cool Form runs validation after any array manipulations.\n\n```js {6-12,18-19}\nimport { useForm, useFieldArray } from \"react-cool-form\";\n\nconst App = () => {\n  const { form } = useForm({\n    // Form-level validation\n    validate: ({ foo }) => {\n      const errors = {};\n\n      if (!foo.length) errors.foo = \"We need a super hero!\";\n\n      return errors;\n    },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n    onError: (errors) => console.log(\"onError: \", errors),\n  });\n  const [fields, { push, remove }] = useFieldArray(\"foo\", {\n    // Field-level validation\n    validate: (value, values /* Form values */) =>\n      !foo.length ? \"We need a super hero!\" : false,\n  });\n\n  return (\n    <form ref={form} noValidate>\n      {fields.map((fieldName, index) => (\n        <div key={fieldName}>\n          <input name={`${fieldName}.name`} />\n          <button type=\"button\" onClick={() => remove(index)}>\n            ➖\n          </button>\n        </div>\n      ))}\n      <button type=\"button\" onClick={() => push({ name: \"Thor\" })}>\n        ➕\n      </button>\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n"
  },
  {
    "path": "docs/getting-started/bundle-size-overview.md",
    "content": "---\nid: bundle-size-overview\ntitle: Bundle Size Overview\n---\n\nReact Cool Form is a tiny size library ([~ 7.1kB](https://bundlephobia.com/result?p=react-cool-form)), it supports [ES modules](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive) format. With the ES modules, modules bundler (e.g. [webpack](https://webpack.js.org) or [Rollup](https://rollupjs.org/guide)) can automatically remove dead-code through the [tree shaking](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking) technique to reduce the bundle size of your app. The size of each module as below:\n\n| Name                                                | Size    |\n| --------------------------------------------------- | ------- |\n| [useForm](../api-reference/use-form)                | ~ 5.8kB |\n| [useFormMethods](../api-reference/use-form-methods) | ~ 108B  |\n| [useFormState](../api-reference/use-form-state)     | ~ 156B  |\n| [useControlled](../api-reference/use-controlled)    | ~ 645B  |\n| [useFieldArray](../api-reference/use-field-array)   | ~ 729B  |\n| [get](../api-reference/utility-functions#get)       | ~ 4B    |\n| [set](../api-reference/utility-functions#set)       | ~ 6B    |\n| [unset](../api-reference/utility-functions#unset)   | ~ 6B    |\n"
  },
  {
    "path": "docs/getting-started/complex-structures.md",
    "content": "---\nid: complex-structures\ntitle: Complex Structures\nhide_table_of_contents: true\n---\n\nWith React Cool Form you can use [dot](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#Dot_notation)-and-[bracket](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#Bracket_notation) notation as the name of a field to create arbitrarily deeply a fields. It's very similar to Lodash's [\\_.set](https://lodash.com/docs/4.17.15#set) method.\n\n:::tip\nSetting `undefined` as a field value deletes the field data from the structure (see [related doc](../api-reference/use-form#setvalue)).\n:::\n\n| Name       | Current structure                   | Value     | Result                      |\n| ---------- | ----------------------------------- | --------- | --------------------------- |\n| foo        | { }                                 | \"rcf\"     | { foo: \"rcf\" }              |\n| foo.bar    | { }                                 | \"rcf\"     | { foo: { bar: \"rcf\" } }     |\n| foo[0]     | { }                                 | \"rcf\"     | { foo: [ \"rcf\" ] }          |\n| foo[1]     | { }                                 | \"rcf\"     | { foo: [ empty, \"rcf\" ] }   |\n| foo.0      | { }                                 | \"rcf\"     | { foo: [ \"rcf\" ] }          |\n| foo[0].bar | { }                                 | \"rcf\"     | { foo: [ { bar: \"rcf\" } ] } |\n| foo        | { foo: \"rcf\" }                      | undefined | { }                         |\n| foo.bar    | { foo: { bar: \"rcf\" }, baz: \"rcf\" } | undefined | { baz: \"rcf\" }              |\n| foo[0]     | { foo: [ { bar: \"rcf\" } ] }         | undefined | { foo: [ empty ] }          |\n\nYou can play around with the following example to get better understanding of how it works:\n\n[![Edit RCF - Complex Structures](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-complex-structures-4x4n1?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm } from \"react-cool-form\";\n\nconst FieldGroup = ({ name, onUpdate, onClear }) => (\n  <>\n    <input name={name} placeholder={name} />\n    <div>\n      <button type=\"button\" onClick={onUpdate}>\n        Update\n      </button>\n      <button type=\"button\" onClick={onClear}>\n        Clear\n      </button>\n    </div>\n  </>\n);\n\nconst App = () => {\n  const { form, setValue } = useForm({\n    defaultValues: {\n      foo: \"\",\n      bar: [],\n      baz: { a: \"\" },\n      qux: [{ a: \"\" }],\n    },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n\n  return (\n    <form ref={form}>\n      <FieldGroup\n        name=\"foo\"\n        onUpdate={() => setValue(\"foo\", \"rcf\")}\n        onClear={() => setValue(\"foo\")}\n      />\n      <FieldGroup\n        name=\"bar[0]\"\n        onUpdate={() => setValue(\"bar[0]\", \"🍋\")}\n        onClear={() => setValue(\"bar[0]\")}\n      />\n      <FieldGroup\n        name=\"baz.a\"\n        onUpdate={() => setValue(\"baz.a\", \"🍉\")}\n        onClear={() => setValue(\"baz.a\")}\n      />\n      <FieldGroup\n        name=\"qux[0].a\"\n        onUpdate={() => setValue(\"qux[0].a\", \"🥝\")}\n        onClear={() => setValue(\"qux[0].a\")}\n      />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n"
  },
  {
    "path": "docs/getting-started/form-state.md",
    "content": "---\nid: form-state\ntitle: Form State\n---\n\nBuilding highly performant forms is the duty of React Cool Form. It minimizes the number of re-renders and provides the best user experience by the following features:\n\n- No unnecessary re-renders by leveraging the power of [uncontrolled components](https://reactjs.org/docs/uncontrolled-components.html)\n- No unnecessary re-renders when [using the form state](#using-the-form-state)\n- No unnecessary re-renders when receives the same form state (since last re-rendering)\n- [Filters the errors of untouched fields](#filter-untouched-field-errors) for better UX (refer to the [UX research](https://www.nngroup.com/articles/errors-forms-design-guidelines) at No.7)\n\nHere we will explore the form state and some [best practices for using it](#best-practices).\n\n## About the Form State\n\nForm state is an `object` containing the following properties:\n\n| Name         | Type      | Description                                                                                                                   |\n| ------------ | --------- | ----------------------------------------------------------------------------------------------------------------------------- |\n| values       | `object`  | The current values of the form.                                                                                               |\n| errors       | `object`  | The current validation errors. [The shape will (should) match the shape of the form's values](./validation-guide#how-to-run). |\n| touched      | `object`  | An object containing all the fields the user has touched/visited.                                                             |\n| isDirty      | `boolean` | Returns `true` if the user modifies any of the fields. `false` otherwise.                                                     |\n| dirty        | `object`  | An object containing all the fields the user has modified.                                                                    |\n| isValidating | `boolean` | Returns `true` if the form is currently being validated. `false` otherwise.                                                   |\n| isValid      | `boolean` | Returns `true` if the form doesn't have any errors (i.e. the `errors` object is empty). `false` otherwise.                    |\n| isSubmitting | `boolean` | Returns `true` if the form is currently being submitted. `false` if otherwise.                                                |\n| isSubmitted  | `boolean` | Returns `true` if the form has been submitted successfully. `false` if otherwise.                                             |\n| submitCount  | `number`  | Number of times the user tried to submit the form. The value will remain until the [form is reset](./reset-form).             |\n\n## Using the Form State\n\nReact Cool Form provides a powerful API: [use](../api-reference/use-form#use) to help us avoid unnecessary re-renders when using the form state.\n\n### Watching the State\n\nDue to the support of [complex structures](./complex-structures), the `use` method allows us to use [dot](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#Dot_notation)-and-[bracket](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#Bracket_notation) notation to get the form state.\n\n```js\nconst { use } = useForm();\n\n// Returns { name: \"Welly\", orders: [\"🍕\", \"🥤\"] }\n// Re-renders the component when either \"values.user\" or \"values.user.<property>\" changes\nconst user = use(\"values.user\");\n\n// Returns \"Welly\", re-renders the component when \"values.user.name\" changes\nconst name = use(\"values.user.name\");\n\n// Returns \"🍕\", re-renders the component when \"values.user.orders\" changes\nconst pizza = use(\"values.user.orders[0]\");\n```\n\nWe can construct an array/object with multiple state-picks inside like the following example:\n\n```js\nconst { use } = useForm();\n\n// Array pick, re-renders the component when either \"values.foo\" or \"values.bar\" changes\nconst [foo, bar] = use([\"values.foo\", \"values.bar\"]);\n\n// Object pick, re-renders the component when either \"values.foo\" or \"values.bar\" changes\nconst { foo, bar } = use({ foo: \"values.foo\", bar: \"values.bar\" });\n```\n\n### Best Practices\n\nEvery time we get a value from the form state via the `use` method, it will listen the changes of the value and trigger re-renders only when necessary. Thus, there're some guidelines for us to use the form state. General speaking, **more frequently updated value(s), need to be accessed more specific, will get more performant**.\n\n```js\nconst { use } = useForm();\n\n// 👎🏻 You can, but not recommended because it will cause the component to update on every value change\nconst values = use(\"values\");\n// 👍🏻 For the form's values, we always recommended getting the target value as specific as possible\nconst fooValue = use(\"values.foo\");\n\n// 👍🏻 It's OK, in most case the form's validation will be triggered less frequently\nconst errors = use(\"errors\");\n// 👍🏻 But if a validation is triggered frequently, get the target error instead\nconst fooError = use(\"errors.foo\");\n\n// 👍🏻 It's OK, they are triggered less frequently\nconst [touched, dirty] = use([\"touched\", \"dirty\"]);\n```\n\n### Shortcut for Accessing the Form's Values\n\nThe form's values might be the most frequent one that we need to get in a specific way, it's kind of verbose. However there's a shortcut for it, we can get the form's values without the `values.` prefix:\n\n```diff\n// Current state: { values: { foo: \"🍎\", bar: \"🍋\", baz: \"🥝\" } }\n\n-const [foo, bar, baz] = use([\"values.foo\", \"values.bar\", \"values.baz\"]);\n+const [foo, bar, baz] = use([\"foo\", \"bar\", \"baz\"]);\n```\n\n### Missing Default Values?\n\nIf we didn't initialize the default value of a field via the [defaultValues option](../api-reference/use-form#defaultvalues) of the `useForm`. The `use` method will lose the value. Because the method is called before the field's initial render. For such cases, we can provide an alternative default value for the `use` method to return as below:\n\n:::note\nIf you need to refer to the status of a [conditional field](../examples/conditional-fields), we recommend to use React state instead.\n:::\n\n```js\nimport { useForm } from \"react-cool-form\";\n\nconst App = () => {\n  const { form, use } = useForm({\n    // Some options...\n  });\n\n  cosnole.log(use(\"values.foo\")); // Returns undefined\n  cosnole.log(use(\"values.foo\", { defaultValues: { foo: \"🍎\" } })); // Returns \"🍎\"\n\n  return (\n    <form ref={form}>\n      {/* The same case as the useControlled's defaultValue option */}\n      <input name=\"foo\" defaultValue=\"🍎\" />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n### Filter Untouched Field Errors\n\nError messages are dependent on the form's validation (i.e. the `errors` object). To avoid annoying the user by seeing an error message while typing, we can filter the errors of untouched fields by enable the `use`'s `errorWithTouched` option (default is `false`).\n\n:::note\nThis feature filters any errors of the untouched fields. So when validating with the [runValidation](../api-reference/use-form#runvalidation), please ensure it's triggered after the field(s) is (are) touched.\n:::\n\n```js\nconst { use } = useForm();\n\n// Current state: { errors: { foo: \"Required\" }, touched: {} }\n// Returns { foo: \"Required\" }\nconst errors = use(\"errors\");\n\n// Current state: { errors: { foo: \"Required\" }, touched: {} }\n// Returns {}\nconst errors = use(\"errors\", { errorWithTouched: true });\n\n// Current state: { errors: { foo: \"Required\" }, touched: { foo: true } }\n// Returns { foo: \"Required\" }\nconst errors = use(\"errors\", { errorWithTouched: true });\n```\n\n👉🏻 See the [Displaying Error Messages](./validation-guide#displaying-error-messages) to learn more about it.\n\n## Isolating Re-rendering\n\nWhenever a [monitored value](#watching-the-state) of the form state is updated, it will trigger re-renders. Re-renders are not bad but **slow re-renders** are (refer to the [article](https://kentcdodds.com/blog/fix-the-slow-render-before-you-fix-the-re-render#unnecessary-re-renders)). So, if you are building a complex form with large number of fields, you can isolate re-rendering at the component level via the [useFormState](../api-reference/use-form-state) hook for better performance. The hook has the similar API design to the `use` method that maintain a consistent DX for us.\n\n:::note\nWe must provide a valid path to use the hook, or it will return `undefined`.\n:::\n\n[![Edit RCF - Isolating Re-rendering](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/intelligent-banach-uqxyx?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm, useFormState } from \"react-cool-form\";\n\nconst checkStrength = (pwd) => {\n  const passed = [/[$@$!%*#?&]/, /[A-Z]/, /[0-9]/, /[a-z]/].reduce(\n    (cal, test) => cal + test.test(pwd),\n    0\n  );\n\n  return { 1: \"Weak\", 2: \"Good\", 3: \"Strong\", 4: \"Very strong\" }[passed];\n};\n\nconst FieldMessage = () => {\n  // Supports single-value-pick, array-values-pick, object-values-pick, and shortcut-values-pick\n  const [error, value] = useFormState([\"errors.password\", \"password\"]);\n\n  return <p>{error || checkStrength(value)}</p>;\n};\n\nconst App = () => {\n  const {} = useForm({\n    defaultValues: { password: \"\" },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <label htmlFor=\"password\">Password</label>\n      <input\n        id=\"password\"\n        name=\"password\"\n        type=\"password\"\n        required\n        minLength={8}\n      />\n      <FieldMessage />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## On State Change Event\n\nThe `useFormState` hook can also play as an event listener to listen for the changes to properties in the form state without triggering re-renders.\n\n:::note\nWe must provide a valid path to use the hook, or the callback won't be triggered.\n:::\n\n```js\nimport { useForm, useFormState } from \"react-cool-form\";\n\nconst App = () => {\n  const { form } = useForm({ defaultValues: { foo: \"\", bar: \"\" } });\n\n  // Triggers callback when form's values changed\n  useFormState(\"values\", ({ foo, bar }) => console.log({ foo, bar }));\n  // Triggers callback when a field value changed\n  useFormState(\"foo\", (foo) => console.log(foo));\n  // Triggers callback when field values changed\n  useFormState([\"foo\", \"bar\"], ([foo, bar]) => console.log([foo, bar]));\n\n  return <form ref={form}>{/* Some fields... */}</form>;\n};\n```\n\n## Reading the State\n\nIf you just want to read the form state without triggering re-renders, there's a [getState](../api-reference/use-form#getstate) method for you.\n\n:::note\nPlease note, this method should be used in an event handler.\n:::\n\n```js {4}\nconst { getState } = useForm();\n\nconst SomeHandler = () => {\n  const [isValid, values] = getState([\"isValid\", \"values\"]);\n\n  if (isValid) createRecordOnServer(values);\n};\n```\n\nWith the method, we can read/construct the data by the following ways:\n\n```js\nconst { getState } = useForm();\n\n// Reading the form state\nconst state = getState();\n\n// Reading a value of the form state\nconst foo = getState(\"values.foo\");\n\n// Shortcut for reading a value\nconst foo = getState(\"foo\");\n\n// Array pick\nconst [foo, bar] = getState([\"values.foo\", \"values.bar\"]);\n\n// Object pick\nconst { foo, bar } = getState({ foo: \"values.foo\", bar: \"values.bar\" });\n```\n"
  },
  {
    "path": "docs/getting-started/form-submission.md",
    "content": "---\nid: form-submission\ntitle: Form Submission\n---\n\nIt's dead simple to submit a form in React Cool Form. All we need to do is to use an `<input type=\"submit\">` or `<button type=\"submit\">` element to fire the form's `onSubmit` event. Moreover, we can also [manually trigger a submission](#manually-triggering-submission) by the [submit](../api-reference/use-form#submit) method of React Cool Form, which can help us overcome any kinds of design challenges easily.\n\n## Submit a Form\n\nThis is the most common case that we submit a form in React Cool Form.\n\n```js\nimport { useForm } from \"react-cool-form\";\n\n// Synchronous submission\nconst submitHandler = (values, options /* Useful helpers */, e) => {\n  console.log(\"onSubmit: \", values);\n};\n\n// Asynchronous submission\nconst submitHandler = async (values, options, e) => {\n  await new Promise((r) => setTimeout(r, 2000));\n  console.log(\"onSubmit: \", values);\n};\n\nconst errorHandler = (errors, options, e) => {\n  console.log(\"onError: \", errors);\n};\n\nconst App = () => {\n  const { form, use } = useForm({\n    defaultValues: { username: \"\", email: \"\" },\n    onSubmit: submitHandler, // The event is triggered once the form is valid\n    onError: errorHandler, // The event is triggered once the form is invalid (optional)\n  });\n  const isSubmitting = use(\"isSubmitting\");\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" required />\n      <input name=\"email\" required />\n      <input type=\"submit\" disabled={isSubmitting} />\n    </form>\n  );\n};\n```\n\n## Submission Phases\n\nYou might be curious about what happened after we clicked the submit button? Whenever a form is attempting to be submitted, React Cool Form will execute the following procedures:\n\n### Pre-submit\n\n- Touches all fields (for displaying errors)\n- Sets `formState.isSubmitting` to `true`\n- Increments `formState.submitCount` by 1\n\n### Validation\n\n- Sets `formState.isValidating` to `true`\n- Runs all [built-in](./validation-guide#built-in-validation), [field-level](./validation-guide#field-level-validation), and [form-level](./validation-guide#form-level-validation) validations asynchronously and [deeply merges the results](./validation-guide#how-to-run).\n- Once the validation is completed, sets `formState.isValidating` to `false`\n\n### Check for Errors\n\nAre there any errors?\n\n- Yes (Invalid): Runs the form's `onError` handler, jumps to \"Post-submit\"\n- No (Valid): Proceeds to \"Submission\"\n\n### Submission\n\n- Runs the form's `onSubmit` handler\n- Once the submission is completed, sets `formState.isSubmitted` to `true`\n\n### Post-submit\n\n- Sets `formState.isSubmitting` to `false`\n\n👉🏻 See the [Form State](./form-state#about-the-form-state) to learn more about it.\n\n## Manually Triggering Submission\n\nFor some reasons (e.g. design requirement, auto-retry, etc.), we might need to trigger a submission manually. However, we can use the [submit](../api-reference/use-form#submit) method to achieve it.\n\n```js {17}\nimport { useForm } from \"react-cool-form\";\n\nconst App = () => {\n  const { form, use, submit } = useForm({\n    defaultValues: { username: \"\", email: \"\" },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n    onError: (errors) => console.log(\"onError: \", errors),\n  });\n  const isSubmitting = use(\"isSubmitting\");\n\n  const handleSubmit = () => {\n    submit();\n  };\n\n  // Handle submit with result, so we don't have to rely on the event handlers\n  const handleSubmit = async () => {\n    const { errors, values } = await submit();\n\n    if (errors) {\n      // Do something for invalid case\n    } else {\n      // Do something for valid case\n    }\n  };\n\n  return (\n    <>\n      <ActionBar>\n        <button onClick={handleSubmit} disabled={isSubmitting}>\n          Submit\n        </button>\n      </ActionBar>\n      <form ref={form} noValidate>\n        {/* ... */}\n      </form>\n    </>\n  );\n};\n```\n"
  },
  {
    "path": "docs/getting-started/getting-started.md",
    "content": "---\nid: getting-started\ntitle: Getting Started\nslug: /\n---\n\nBuilding forms in [React](https://reactjs.org) might be a challenge. We have to face many tedious things like form data, validation, submission, and more 🤯.\n\nAs a React developer, there're two strategies for implementing forms, the [controlled components](https://reactjs.org/docs/forms.html#controlled-components) and [uncontrolled components](https://reactjs.org/docs/uncontrolled-components.html), each has its advantages and timing of use. The controlled components serve form state as [the single source of truth](https://en.wikipedia.org/wiki/Single_source_of_truth). However, the uncontrolled components make our code more **concise** and **performant**.\n\nReact Cool Form combines these advantages and references the [UX research](https://www.nngroup.com/articles/errors-forms-design-guidelines) of [Nielsen Norman Group](https://www.nngroup.com) as the basis for our [API](./api-reference/use-form) design to help you conquer all kinds of forms 👊🏻.\n\n## Requirement\n\nTo use React Cool Form, you must use `react@16.8.0` or greater which includes hooks.\n\n## Installation\n\nThis package is distributed via [npm](https://www.npmjs.com/package/react-cool-form).\n\n```sh npm2yarn\n$ npm install --save react-cool-form\n```\n\n:::info\nReact Cool Form supports all major browsers. For older browsers (e.g. IE11) without the `async/await`, `Promise`, and ES6+ features, you'll need to include a polyfill such as [core-js](https://github.com/zloirock/core-js).\n:::\n\n## CDN\n\nIf you're not using a module bundler or package manager. We also provide a [UMD](https://github.com/umdjs/umd) build which is available over the [unpkg.com](https://unpkg.com) CDN. Simply use a `<script>` tag to add it after [React CDN links](https://reactjs.org/docs/cdn-links.html) as below:\n\n<!-- prettier-ignore-start -->\n```html\n<script crossorigin src=\"https://unpkg.com/react/umd/react.production.min.js\"></script>\n<script crossorigin src=\"https://unpkg.com/react-dom/umd/react-dom.production.min.js\"></script>\n<!-- react-cool-form comes here -->\n<script crossorigin src=\"https://unpkg.com/react-cool-form/dist/index.umd.production.min.js\"></script>\n```\n<!-- prettier-ignore-end -->\n\nThen you can access it via the `window.ReactCoolForm.<moduleName>` variables.\n\n## Example\n\nHere's the basic concept of how it rocks:\n\n[![Edit RCF - Quick start](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-quick-start-j8p1l?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm } from \"react-cool-form\";\n\nconst Field = ({ label, id, error, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n    {error && <p>{error}</p>}\n  </div>\n);\n\nconst App = () => {\n  const { form, use } = useForm({\n    // (Strongly advise) Provide the default values\n    defaultValues: { username: \"\", email: \"\", password: \"\" },\n    // The event only triggered when the form is valid\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  // We can enable the \"errorWithTouched\" option to filter the error of an un-blurred field\n  // Which helps the user focus on typing without being annoyed by the error message\n  const errors = use(\"errors\", { errorWithTouched: true }); // Default is \"false\"\n\n  return (\n    <form ref={form} noValidate>\n      <Field\n        label=\"Username\"\n        id=\"username\"\n        name=\"username\"\n        // Support built-in validation\n        required\n        error={errors.username}\n      />\n      <Field\n        label=\"Email\"\n        id=\"email\"\n        name=\"email\"\n        type=\"email\"\n        required\n        error={errors.email}\n      />\n      <Field\n        label=\"Password\"\n        id=\"password\"\n        name=\"password\"\n        type=\"password\"\n        required\n        minLength={8}\n        error={errors.password}\n      />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n✨ Pretty easy right? React Cool Form is more powerful than you think. Let's keep exploring!\n"
  },
  {
    "path": "docs/getting-started/integration-an-existing-form.md",
    "content": "---\nid: integration-an-existing-form\ntitle: Integration an Existing Form\n---\n\n\"Easy to use\" is one of the core design principles of React Cool Form, the library is built on top of React [hook](https://reactjs.org/docs/hooks-custom.html#using-a-custom-hook). So it's easy to be integrated with an existing form without too much effort.\n\n## Hook into A Form\n\nTo use React Cool Form, we just need to attach the [form](../api-reference/use-form#form) method to the target element via the `ref` attribute. It acts as a **delegator** that will take care of all the values of [input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input), [select](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select), and [textarea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea) for us.\n\n[![Edit RCF - Basic](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-basic-17fz0?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm } from \"react-cool-form\";\n\nconst Field = ({ label, id, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n  </div>\n);\n\nconst Select = ({ label, id, children, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <select id={id} {...rest}>\n      {children}\n    </select>\n  </div>\n);\n\nconst Textarea = ({ label, id, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <textarea id={id} {...rest} />\n  </div>\n);\n\nconst App = () => {\n  const { form } = useForm({\n    // (Strongly advise) Provide the default values\n    defaultValues: { firstName: \"\", lastName: \"\", framework: \"\", message: \"\" },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n\n  return (\n    // We can use \"noValidate\" to disable browser's interactive validation\n    <form ref={form} noValidate>\n      <Field label=\"First Name\" id=\"first-name\" name=\"firstName\" />\n      <Field label=\"Last Name\" id=\"last-name\" name=\"lastName\" />\n      <Select label=\"Framework\" id=\"framework\" name=\"framework\">\n        <option value=\"\">I'm interesting in...</option>\n        <option value=\"react\">React</option>\n        <option value=\"vue\">Vue</option>\n        <option value=\"angular\">Angular</option>\n        <option value=\"svelte\">Svelte</option>\n      </Select>\n      <Textarea label=\"Message\" id=\"message\" name=\"message\" />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\nIf you need to use the `ref` of form for other purpose, you can share the `ref` by the following way:\n\n```js {10}\nimport { useRef } from \"react\";\nimport { useForm } from \"react-cool-form\";\n\nconst App = () => {\n  const formRef = useRef();\n  const { form } = useForm();\n\n  const setRef = (element) => {\n    if (element) {\n      formRef.current = element;\n      form(element);\n    }\n  };\n\n  return <form ref={form}>{/* Some fields... */}</form>;\n};\n```\n\n## Without Using a `<form>` Element\n\nReact Cool Form is not limited to actual forms. It can be used with any container where inputs are used.\n\n[![Edit RCF - Without Form Element](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-without-form-element-wvctm?fontsize=14&hidenavigation=1&theme=dark)\n\n```js {19,38}\nimport { useForm } from \"react-cool-form\";\n\nconst Field = ({ label, id, error, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n    {error && <p>{error}</p>}\n  </div>\n);\n\nconst App = () => {\n  const { form, use, submit } = useForm({\n    defaultValues: { email: \"\", password: \"\" },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  const errors = use(\"errors\", { errorWithTouched: true });\n\n  return (\n    <div ref={form}>\n      <Field\n        label=\"Email\"\n        id=\"email\"\n        name=\"email\"\n        type=\"email\"\n        required\n        error={errors.email}\n      />\n      <Field\n        label=\"Password\"\n        id=\"password\"\n        name=\"password\"\n        type=\"password\"\n        required\n        minLength={8}\n        error={errors.password}\n      />\n      {/* We need to manually submit the form */}\n      <button onClick={submit}>Submit</button>\n    </div>\n  );\n};\n```\n\n## Exclude Fields\n\nYou can tell React Cool Form to exclude field(s) via the pre-defined `data-rcf-exclude` attribute or the [excludeFields](../api-reference/use-form#excludefields) option, depending on your case.\n\n[![Edit RCF - Conditional Fields](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-conditional-fields-rnxe6?fontsize=14&hidenavigation=1&theme=dark)\n\n```js {7,20}\nimport { useState } from \"react\";\nimport { useForm } from \"react-cool-form\";\n\nconst App = () => {\n  const { from } = useForm({\n    defaultValues: { username: \"\", email: \"\" },\n    // excludeFields: [\"more\"], // You can also exclude the field here by passing in name/id/class\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  const [toggle, setToggle] = useState(false);\n\n  return (\n    <form ref={form}>\n      <input name=\"username\" />\n      <input name=\"email\" type=\"email\" />\n      <input\n        name=\"more\" // Used for the \"excludeFields\" option\n        type=\"checkbox\"\n        onChange={() => setToggle(!toggle)}\n        data-rcf-exclude // Exclude the fields via the pre-defined data attribute\n      />\n      {toggle && (\n        <>\n          <input name=\"option\" type=\"radio\" value=\"🍎\" defaultChecked />\n          <input name=\"option\" type=\"radio\" value=\"🥝\" />\n          <input name=\"option\" type=\"radio\" value=\"🍋\" />\n        </>\n      )}\n    </form>\n  );\n};\n```\n"
  },
  {
    "path": "docs/getting-started/reset-form.md",
    "content": "---\nid: reset-form\ntitle: Reset Form\n---\n\nThere're two common ways to reset all form data: [reset after form submission](#reset-after-form-submission) and [reset form manually](#reset-form-manually). You might ask \"how about the reset button?\" Well... according to the [UX research](https://www.nngroup.com/articles/reset-and-cancel-buttons), which summarized: **\"Most Web forms would have improved usability if the Reset button was removed.\"** So, generally not recommend but [still supported](#reset-button-not-recommended).\n\n## Reset After Form Submission\n\nWe can use React Cool Form's [reset](../api-reference/use-form#reset) method (also available from the [onSubmit](../api-reference/use-form#onsubmit) handler) to restore the form to its default values as well as clear/reset all the [related state](./form-state#about-the-form-state).\n\n[![Edit RCF - Reset Form](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-reset-form-uikxg?fontsize=14&hidenavigation=1&theme=dark)\n\n```js {13}\nimport { useForm } from \"react-cool-form\";\n\nconst Field = ({ label, id, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n  </div>\n);\n\nconst App = () => {\n  const { form } = useForm({\n    defaultValues: { firstName: \"Welly\", lastName: \"Shen\" },\n    onSubmit: (values, { reset }) => reset(),\n    onReset: (values, options /* Useful helpers */, e) =>\n      console.log(\"onReset: \", values), // Triggered on form reset\n  });\n\n  return (\n    <form ref={form}>\n      <Field label=\"First Name\" id=\"first-name\" name=\"firstName\" />\n      <Field label=\"Last Name\" id=\"last-name\" name=\"lastName\" />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## Reset Form Manually\n\nWe can also lazily set (or update) the form's default values by the `reset` method.\n\n[![Edit RCF - Lazy Default Values](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-lazy-default-values-qxvlz?fontsize=14&hidenavigation=1&theme=dark)\n\n```js {11}\nimport { useEffect } from \"react\";\nimport { useForm } from \"react-cool-form\";\n\nconst App = () => {\n  const { form, reset } = useForm({\n    onReset: (values, options, e) => console.log(\"onReset: \", values), // Triggered on form reset\n  });\n\n  useEffect(async () => {\n    const data = await fetchData(\"https://form-values\"); // Returns { firstName: \"Welly\", lastName: \"Shen\" }\n    reset(data);\n  }, [reset]);\n\n  const handleFormReset = async () => {\n    const data = await fetchData();\n    reset(data);\n  };\n\n  return (\n    <form ref={form}>\n      <Field label=\"First Name\" id=\"first-name\" name=\"firstName\" />\n      <Field label=\"Last Name\" id=\"last-name\" name=\"lastName\" />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## Reset Button (not recommended)\n\nAs the [UX research](https://www.nngroup.com/articles/reset-and-cancel-buttons) mentioned: **\"Most Web forms would have improved usability if the Reset button was removed.\"** But in case you need it, React Cool Form supports the [onreset](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onreset) internally. All we need to do is to provide an `<input type=\"reset\">` to the user.\n\n```js {11}\nimport { useForm } from \"react-cool-form\";\n\nconst App = () => {\n  const { form, reset } = useForm({\n    onReset: (values, options, e) => console.log(\"onReset: \", values), // Triggered on form reset\n  });\n\n  return (\n    <form ref={form}>\n      {/* ... */}\n      <input type=\"reset\" />\n    </form>\n  );\n};\n```\n"
  },
  {
    "path": "docs/getting-started/typescript-support.md",
    "content": "---\nid: typescript-support\ntitle: TypeScript Support\n---\n\nReact Cool Form is written in [TypeScript](https://www.typescriptlang.org), so the library's types will always be up-to-date. When working with TypeScript, we can define a `FormValues` type to support the form's values.\n\n[![Edit RCF - TypeScript](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-typescript-46x8n?fontsize=14&hidenavigation=1&theme=dark)\n\n```tsx\nimport { useForm } from \"react-cool-form\";\n\ninterface FormValues {\n  firstName: string;\n  lastName: string;\n}\n\nconst App = () => {\n  const { form } = useForm<FormValues>({\n    defaultValues: {\n      firstName: \"Welly\",\n      lastName: true, // ❌ Type \"boolean\" is not assignable to type \"string\"\n    },\n    onSubmit: (values) => {\n      console.log(\"First Name: \", values.firstName);\n      console.log(\"Middle Name: \", values.middleName); // ❌ Property \"middleName\" does not exist on type \"FormValues\"\n    },\n  });\n\n  return (\n    <form ref={form}>\n      <input name=\"firstName\" />\n      <input name=\"lastName\" />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## TypeScript and Hooks\n\nWe can provide the `FormValues` type to the following hooks:\n\n```tsx\ninterface FormValues {\n  firstName: string;\n  lastName: string;\n}\n\nconst methods = useForm<FormValues>();\n\nconst methods = useFormMethods<FormValues>();\n\nconst props = useFormState<FormValues>();\n\nconst props = useControlled<FormValues>();\nＦ;\n// Working without \"validate\" option\nconst props = useFieldArray<FieldValue>();\n// Working with \"validate\" option\nconst props = useFieldArray<FieldValue, FormValues>({\n  validate: (value) => {\n    /* ... */\n  },\n});\n```\n\n## Making Field's Name Type-safe\n\nSome folks are asking about the type-safe of a field's name, however we can achieve that via TypeScript's [Enums](https://www.typescriptlang.org/docs/handbook/enums.html).\n\n```tsx\nenum FieldNames {\n  \"name\" = \"name\",\n}\n\nconst App = () => {\n  const { form } = useForm({\n    defaultValues: {\n      [FieldNames.email]: \"Welly\", // ❌ Property \"email\" does not exist on type \"typeof FieldNames\"\n    },\n  });\n\n  return (\n    <form ref={form}>\n      <input\n        name={FieldNames.email} // ❌ Property \"email\" does not exist on type \"typeof FieldNames\"\n      />\n    </form>\n  );\n};\n```\n\n🧐 You can dig more useful [types](https://github.com/wellyshen/react-cool-form/blob/master/src/types/react-cool-form.d.ts) of this library to build a strongly typed form.\n"
  },
  {
    "path": "docs/getting-started/validation-guide.md",
    "content": "---\nid: validation-guide\ntitle: Validation Guide\n---\n\nReact Cool Form supports a wide range of **synchronous** and **asynchronous** validation strategies for [built-in](#built-in-validation), [form-level](#form-level-validation), and [field-level](#field-level-validation) validation to cover all the cases that you need.\n\n## Built-in Validation\n\nWe support [HTML form validation](https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation#Using_built-in_form_validation) out of the box, a quick and easy way for form validation.\n\n[![Edit RCF - Built-in validation](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-built-in-validation-1h28u?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm } from \"react-cool-form\";\n\nconst App = () => {\n  const { form } = useForm({\n    defaultValues: { username: \"\", email: \"\", password: \"\" },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n    onError: (errors) => console.log(\"onError: \", errors),\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" required />\n      <input name=\"email\" type=\"email\" required />\n      <input name=\"password\" type=\"password\" required minLength={8} />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\nSome validation attributes such as [minLength](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/minlength), [maxLength](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/maxlength), [min](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/min), and [max](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/max) are designed to validate a field once it has been edited by the user. Therefore when [manually triggering](#manually-triggering-validation) these validations, use the [pattern](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern) attribute or custom validation instead.\n\n```js\n<input name=\"password\" type=\"password\" required pattern=\".{6,}\" /> // 6 characters minimum\n```\n\n## Form-level Validation\n\nThe [validate](../api-reference/use-form#validate) option provides a convenient way to access the complete `values` of the form (a.k.a [formState.values](./form-state#about-the-form-state)), which is useful to validate by dependent fields **during both editing (e.g. onChange, onBlur) and submission phases**.\n\n:::note\nPlease ensure the shape of the `errors` matches the shape of form's `values`. If you're dealing with [complex structures](./complex-structures), we've provided a set of [utility functions](../api-reference/utility-functions) to help you get shit done 💩.\n:::\n\n[![Edit RCF - Form-level validation](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-form-level-validation-2if7r?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm } from \"react-cool-form\";\n\n// Synchronous validation\nconst validate = (values) => {\n  const errors = {};\n\n  if (!values.email.length) {\n    errors.email = \"Required\";\n  } else if (!/^[A-Z0-9._-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$/i.test(values.email)) {\n    errors.email = \"Invalid email address\";\n  }\n\n  // ...\n\n  return errors;\n};\n\n// Asynchronous validation\nconst validate = async (values) => {\n  const errors = {};\n  const hasUser = await validateOnServer(values.username);\n\n  if (!hasUser) errors.username = \"User doesn't exist\";\n\n  // ...\n\n  return errors;\n};\n\nconst App = () => {\n  const { form, use } = useForm({\n    defaultValues: { username: \"\", email: \"\" },\n    validate,\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n    onError: (errors) => console.log(\"onError: \", errors),\n  });\n\n  console.log(\"Form is validating: \", use(\"isValidating\"));\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" />\n      <input name=\"email\" type=\"email\" />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\nIn addition to write your own logic, it's also possible to run form-level validation with any 3rd-party libraries (e.g. [Yup](https://github.com/jquense/yup), [Joi](https://github.com/sideway/joi), and many others). Let's see how to make it by the following example:\n\n[![Edit RCF - Schema](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-schema-lsk6f?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm, set } from \"react-cool-form\";\nimport * as yup from \"yup\";\nimport Joi from \"joi\";\n\n// Reusable validation function for Yup\nconst validateWithYup = (schema) => async (values) => {\n  let errors = {};\n\n  try {\n    await schema.validate(values, { abortEarly: false });\n  } catch (yupError) {\n    // Convert the yup errors to field errors\n    // Use the \"set\" helper to assign properties for both \"shallow\" and \"deep\" (nested fields) object\n    yupError.inner.forEach(({ path, message }) => set(errors, path, message));\n  }\n\n  return errors;\n};\n\n// Reusable validation function for Joi\nconst validateWithJoi = (schema) => (values) => {\n  let errors = {};\n\n  const { error: joiError } = schema.validate(values, { abortEarly: false });\n\n  if (joiError)\n    joiError.details.forEach(({ path, message }) =>\n      set(errors, path[0], message)\n    );\n\n  return errors;\n};\n\nconst yupSchema = yup.object().shape({\n  username: yup.string().required(),\n  email: yup.string().email().required(),\n  password: yup.string().required().min(6),\n});\n\nconst JoiSchema = Joi.object({\n  username: Joi.string().required(),\n  email: Joi.string().email({ tlds: false }).required(),\n  password: Joi.string().required().min(6),\n});\n\nconst App = () => {\n  const { form } = useForm({\n    defaultValues: { username: \"\", email: \"\", password: \"\" },\n    validate: validateWithYup(yupSchema),\n    // validate: validateWithJoi(JoiSchema),\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n    onError: (errors) => console.log(\"onError: \", errors),\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" />\n      <input name=\"email\" type=\"email\" />\n      <input name=\"password\" type=\"password\" />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## Field-level Validation\n\nReact Cool Form provides the [field](../api-reference/use-form#field) method for field-level validation. We can also access the form `values` with the method to validate by dependent fields **during the submission phase**. Simply register your validator via the `ref` attribute of a field like the following example:\n\n[![Edit RCF - Field-level validation](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-field-level-validation-dbklg?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm } from \"react-cool-form\";\n\n// Synchronous validation\nconst validateEmail = (value, values /* Form values */) => {\n  if (!value) {\n    return \"Required\";\n  } else if (!/^[A-Z0-9._-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$/i.test(value)) {\n    return \"Invalid email address\";\n  }\n};\n\n// Asynchronous validation\nconst validateUsername = async (value, values /* Form values */) => {\n  const hasUser = await validateOnServer(value);\n  if (!hasUser) return \"User doesn't exist\";\n};\n\nconst App = () => {\n  const { form, field, use } = useForm({\n    defaultValues: { username: \"\", email: \"\" },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n    onError: (errors) => console.log(\"onError: \", errors),\n  });\n\n  console.log(\"Form is validating: \", use(\"isValidating\"));\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" ref={field(validateUsername)} />\n      <input name=\"email\" type=\"email\" ref={field(validateEmail)} />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\nThe `field` method can not only be used for validating but also converting data type. When they are used together, just tweak the code as below:\n\n```js\n<input\n  name=\"username\"\n  ref={field({\n    validate: validateUsername,\n    valueAsNumber: true,\n    // More options...\n  })}\n/>\n```\n\n## Manually Triggering Validation\n\nWe can manually trigger built-in, field-level, and form-level validation with React Cool Form's [`runValidation`](../api-reference/use-form#runvalidation) method.\n\n```js\nimport { useForm } from \"react-cool-form\";\n\nconst validate = (values) => {\n  const errors = {};\n\n  // To validate a single field, the property of the \"errors\" should reflect the name of the dependent field\n  if (!values.username.length) errors.username = \"Required\";\n\n  if (!values.email.length) {\n    errors.email = \"Required\";\n  } else if (!/^[A-Z0-9._-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$/i.test(values.email)) {\n    errors.email = \"Invalid email address\";\n  }\n\n  return errors;\n};\n\nconst App = () => {\n  const { form, runValidation } = useForm({\n    defaultValues: { firstName: \"\", lastName: \"\", email: \"\" },\n    validate,\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n    onError: (errors) => console.log(\"onError: \", errors),\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"firstName\" required />\n      <input name=\"lastName\" required />\n      <input name=\"email\" type=\"email\" required />\n      {/* Validate single field */}\n      <button onClick={() => runValidation(\"firstName\")}>\n        Validate Single\n      </button>\n      {/* Validate multiple fields */}\n      <button onClick={() => runValidation([\"firstName\", \"lastName\"])}>\n        Validate Multiple\n      </button>\n      {/* Validate the form (i.e. all the fields) */}\n      <button onClick={() => runValidation()}>Validate All</button>\n      {/* With result */}\n      <button\n        onClick={async () => {\n          const isValid = await runValidation();\n          console.log(\"The form is: \", isValid ? \"valid\" : \"invalid\");\n        }}\n      >\n        Validate Results\n      </button>\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## When/How Does Validation Run?\n\nBy default, React Cool Form runs all the validation methods as follows. You can tell React Cool Form when to run them by changing the [validateOnChange](../api-reference/use-form#validateonchange) and/or [validateOnBlur](../api-reference/use-form#validateonblur), depending on your needs.\n\n### When to Run\n\n| Event/method                                               | Target         | Timing                                                                                                                     |\n| ---------------------------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------- |\n| `onChange`                                                 | Individual     | Whenever the value of a field has been changed.                                                                            |\n| [`setValue`](../api-reference/use-form#setvalue)           | Individual     | Whenever the value of a field has been set.                                                                                |\n| `onBlur`                                                   | Individual     | Whenever a field has been touched. **If a validation method has been run by the `onChange` event, it won't be run again**. |\n| `onSubmit`                                                 | All            | Whenever a submission attempt is made.                                                                                     |\n| [`submit`](../api-reference/use-form#submit)               | All            | Whenever a submission attempt is made manually.                                                                            |\n| [`runValidation`](../api-reference/use-form#runvalidation) | Individual/All | Manually running validation for the field(s) or form.                                                                      |\n\n### How to Run\n\nWhen validating with mixed ways, the results are deeply merged according to the following order:\n\n1. Built-in validation\n2. Field-level validation\n3. Form-level validation\n\n:::note\nTo make the validation result of each field works correctly with the [individual](#when-to-run) target events or methods. When using [form-level validation](#form-level-validation), please ensure the shape of the `errors` matches the form's `values`.\n:::\n\n## Displaying Error Messages\n\nAll errors are stored in the [formState.errors](./form-state#about-the-form-state), we can display error messages by accessing the `errors` object via the [use](../api-reference/use-form#use) method. The method provides an `errorWithTouched` option to help us filtering the errors of untouched fields, which is designed based on the [Errors in Forms design guideline](https://www.nngroup.com/articles/errors-forms-design-guidelines) (No.7). You can enable the feature by setting the option to `true` (see [related doc](./form-state#filter-untouched-field-errors)).\n\n[![Edit RCF - Quick start](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rcf-quick-start-j8p1l?fontsize=14&hidenavigation=1&theme=dark)\n\n```js\nimport { useForm } from \"react-cool-form\";\n\nconst App = () => {\n  const { form, use } = useForm({\n    defaultValues: { username: \"\", email: \"\", password: \"\" },\n    onSubmit: (values) => console.log(\"onSubmit: \", values),\n  });\n  // We can enable the \"errorWithTouched\" option to filter the error of an un-blurred field\n  // Which helps the user focus on typing without being annoyed by the error message\n  const errors = use(\"errors\", { errorWithTouched: true }); // Default is \"false\"\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" required />\n      {errors.username && <p>{errors.username}</p>}\n      <input name=\"email\" type=\"email\" required />\n      {errors.email && <p>{errors.email}</p>}\n      <input name=\"password\" type=\"password\" required minLength={8} />\n      {errors.password && <p>{errors.password}</p>}\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\nWhen dealing with [nested fields](./complex-structures), you can shallow the errors and get free from checking valid chained properties (e.g. use `?.`) by the [array/object pick feature](./form-state#watching-the-state) of the `use` method.\n\n```js\nconst App = () => {\n  // ...\n\n  const [username, email, password] = use(\n    [\"foo.username\", \"foo.email\", \"foo.password\"],\n    {\n      errorWithTouched: true,\n    }\n  );\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"foo.username\" required />\n      {username && <p>{username}</p>}\n      <input name=\"foo.email\" type=\"email\" required />\n      {email && <p>{email}</p>}\n      <input name=\"foo.password\" type=\"password\" required minLength={8} />\n      {password && <p>{password}</p>}\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\nThe built-in validation is **turned on** by default. Which provides two forms of error reports: the `message` (refer to [validationMessage](https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validationMessage)) and the `state` (refer to [ValidityState](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState)). You can configure (or disable) it by the [builtInValidationMode](../api-reference/use-form#builtonvalidationmode) option.\n\n```js {5}\nimport { useForm } from \"react-cool-form\";\n\nconst App = () => {\n  const { form, use } = useForm({\n    builtInValidationMode: \"message\" | \"state\" | false, // Default is \"message\"\n    // More options...\n  });\n  const errors = use(\"errors\");\n\n  console.log(\"Message mode: \", errors); // Returns a localized message that describes the validation constraints that the field does not satisfy (if any)\n  console.log(\"State mode: \", errors); // Returns the \"key\" of the invalid property of the ValidityState (if any)\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" required />\n      <input type=\"submit\" />\n    </form>\n  );\n};\n```\n\n## Focus On Error\n\nWhen the user submits a form that fails the validation, React Cool Form will apply focus to the first field with an error. The focus order is based on the field order (i.e. top-to-bottom and left-to-right), however you can change the order by the [focusOnError](../api-reference/use-form#focusonerror) option.\n"
  },
  {
    "path": "examples/README.md",
    "content": "# Examples\n\n📚 A collection of code examples, let's [check it out](https://react-cool-form.netlify.app/docs/examples/basic).\n"
  },
  {
    "path": "examples/arrays-and-lists/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm, useFieldArray } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nlet count = 0;\n\nfunction App() {\n  count++;\n\n  const { form, focus, use } = useForm({\n    defaultValues: {\n      foo: [\n        { name: \"Iron Man\", quote: \"I'm Iron Man\" },\n        { name: \"Thor\", quote: \"I Knew It\" },\n        { name: \"Hulk\", quote: \"Bout Time\" }\n      ]\n    },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n  const [fields, { push, insert, remove, swap, move }] = useFieldArray(\"foo\");\n\n  /* console.log(\n    \"Field value: \",\n    use({ value: \"foo\", touched: \"touched.foo\", dirty: \"dirty.foo\" })\n  ); */\n\n  return (\n    <form ref={form}>\n      <div className=\"count\">Render {count} times</div>\n      {/* The first parameter of the callback supplies you a field name (e.g. foo[0], foo[1]) */}\n      {fields.map((fieldName, index) => (\n        // Use the \"fieldName\" as the key\n        <div key={fieldName}>\n          {/* Use the \"fieldName\" + \"YOUR PATH\" as the name */}\n          <input name={`${fieldName}.name`} />\n          <input name={`${fieldName}.quote`} />\n          <button type=\"button\" onClick={() => remove(index)}>\n            REMOVE\n          </button>\n        </div>\n      ))}\n      <div>\n        <button\n          type=\"button\"\n          onClick={() => {\n            push({ name: \"Loki\", quote: \"Your Savior Is Here\" });\n            // We need to wait for the item rendered (delay = 0 is acceptable) then apply focus to the first field\n            focus(`foo[${fields.length}]`, 300);\n            // You can also apply focus to a specified field\n            // focus(`foo[${fields.length}].quote`, 300);\n          }}\n        >\n          PUSH\n        </button>\n        <button\n          type=\"button\"\n          onClick={() =>\n            insert(0, {\n              name: \"Spider Man\",\n              quote: \"Your Friendly Neighborhood Spider-Man\"\n            })\n          }\n        >\n          INSERT\n        </button>\n        <button type=\"button\" onClick={() => swap(0, 1)}>\n          SWAP\n        </button>\n        <button type=\"button\" onClick={() => move(2, 0)}>\n          MOVE\n        </button>\n      </div>\n      <input type=\"submit\" />\n      <input type=\"reset\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/arrays-and-lists/package.json",
    "content": "{\n  \"name\": \"rcf-arrays-and-lists\",\n  \"description\": \"The arrays and lists example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/arrays-and-lists/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 3rem auto 0;\n  width: 28rem;\n\n  div {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n\n    &.count {\n      justify-content: center;\n      margin-bottom: 1.5rem;\n      padding: 0.25rem 0;\n      color: #fff;\n      background: #333;\n      border-radius: 4px;\n    }\n\n    input {\n      width: 13.5rem;\n\n      &:first-of-type {\n        width: 6.5rem;\n      }\n    }\n\n    button {\n      width: 6.5rem;\n      height: 2rem;\n      border: none;\n      border-radius: 4px;\n      border: 1px solid #fff;\n      color: #fff;\n      background: transparent;\n      cursor: pointer;\n    }\n\n    &:last-of-type {\n      margin-top: 0.5rem;\n    }\n  }\n\n  input {\n    margin: 0.5rem 0;\n    padding: 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"],\n  input[type=\"reset\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    cursor: pointer;\n  }\n\n  input[type=\"submit\"] {\n    margin-top: 2rem;\n    color: #fff;\n    background: #0971f1;\n  }\n}\n"
  },
  {
    "path": "examples/basic/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst Field = ({ label, id, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n  </div>\n);\n\nconst Select = ({ label, id, children, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <select id={id} {...rest}>\n      {children}\n    </select>\n  </div>\n);\n\nconst Textarea = ({ label, id, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <textarea id={id} {...rest} />\n  </div>\n);\n\nfunction App() {\n  const { form } = useForm({\n    defaultValues: { firstName: \"\", lastName: \"\", framework: \"\", message: \"\" },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n\n  return (\n    <form ref={form}>\n      <Field label=\"First Name\" id=\"first-name\" name=\"firstName\" />\n      <Field label=\"Last Name\" id=\"last-name\" name=\"lastName\" />\n      <Select label=\"Framework\" id=\"framework\" name=\"framework\">\n        <option value=\"\">I'm interesting in...</option>\n        <option value=\"react\">React</option>\n        <option value=\"vue\">Vue</option>\n        <option value=\"angular\">Angular</option>\n        <option value=\"svelte\">Svelte</option>\n      </Select>\n      <Textarea label=\"Message\" id=\"message\" name=\"message\" />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/basic/package.json",
    "content": "{\n  \"name\": \"rcf-basic\",\n  \"description\": \"The basic example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/basic/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 3rem auto 0;\n  width: 24rem;\n\n  div {\n    width: inherit;\n    margin-bottom: 1rem;\n  }\n\n  label {\n    display: block;\n    color: #fff;\n  }\n\n  input,\n  select,\n  textarea {\n    margin: 0.5rem 0;\n    padding: 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n\n  textarea {\n    height: 5rem;\n  }\n}\n"
  },
  {
    "path": "examples/built-in-validation/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nfunction App() {\n  const { form } = useForm({\n    defaultValues: { username: \"\", email: \"\", password: \"\" },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2)),\n    onError: (errors) => console.log(\"onError: \", errors)\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" placeholder=\"Username\" required />\n      <input name=\"email\" type=\"email\" placeholder=\"Email\" required />\n      <input\n        name=\"password\"\n        type=\"password\"\n        placeholder=\"Password\"\n        required\n        minLength={8}\n      />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/built-in-validation/package.json",
    "content": "{\n  \"name\": \"rcf-built-in-validation\",\n  \"description\": \"The built-in validation example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/built-in-validation/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  input {\n    margin-bottom: 1.5rem;\n    padding: 0 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/checkboxes/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst Field = ({ label, id, ...rest }) => (\n  <>\n    <input id={id} {...rest} />\n    <label htmlFor={id}>{label}</label>\n  </>\n);\n\nconst Group = ({ title, children, error }) => (\n  <div>\n    <fieldset>\n      <legend>{title}</legend>\n      {children}\n    </fieldset>\n    {error && <p>{error}</p>}\n  </div>\n);\n\nfunction App() {\n  const { form, use } = useForm({\n    defaultValues: { single: true, multiple: [] },\n    validate: (values) => {\n      if (!values.multiple.length) return { multiple: \"Required\" };\n    },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <Group title=\"Single\">\n        <Field label=\"😎\" id=\"single\" name=\"single\" type=\"checkbox\" />\n      </Group>\n      <Group title=\"Multitple\" error={use(\"errors.multiple\")}>\n        <Field\n          id=\"apple\"\n          name=\"multiple\"\n          value=\"🍎\"\n          label=\"🍎\"\n          type=\"checkbox\"\n        />\n        <Field\n          id=\"lemon\"\n          name=\"multiple\"\n          value=\"🍋\"\n          label=\"🍋\"\n          type=\"checkbox\"\n        />\n        <Field\n          id=\"kiwi\"\n          name=\"multiple\"\n          value=\"🥝\"\n          label=\"🥝\"\n          type=\"checkbox\"\n        />\n      </Group>\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/checkboxes/package.json",
    "content": "{\n  \"name\": \"rcf-checkboxes\",\n  \"description\": \"The checkboxes example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/checkboxes/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n  color: #fff;\n\n  div {\n    margin-bottom: 2rem;\n  }\n\n  fieldset {\n    border-radius: 4px;\n    border-color: #555;\n    box-shadow: 0;\n  }\n\n  input {\n    margin-right: 0.5rem;\n\n    &:not(:first-of-type) {\n      margin-left: 1rem;\n    }\n  }\n\n  input[type=\"submit\"] {\n    width: inherit;\n    height: 2.5rem;\n    border: none;\n    border-radius: 4px;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n\n  p {\n    margin-top: 0.5rem;\n    color: #ff9900;\n  }\n}\n"
  },
  {
    "path": "examples/complex-structures/.codesandbox/workspace.json",
    "content": "{\n  \"responsive-preview\": {\n    \"Mobile\": [\n      320,\n      675\n    ],\n    \"Tablet\": [\n      1024,\n      765\n    ],\n    \"Desktop\": [\n      1400,\n      800\n    ],\n    \"Desktop HD\": [\n      1920,\n      1080\n    ]\n  }\n}"
  },
  {
    "path": "examples/complex-structures/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst FieldGroup = ({ name, onUpdate, onClear }) => (\n  <>\n    <input name={name} placeholder={name} />\n    <div>\n      <button type=\"button\" onClick={onUpdate}>\n        UPDATE\n      </button>\n      <button type=\"button\" onClick={onClear}>\n        CLEAR\n      </button>\n    </div>\n  </>\n);\n\nfunction App() {\n  const { form, setValue } = useForm({\n    defaultValues: {\n      foo: \"\",\n      bar: [],\n      baz: { a: \"\" },\n      qux: [{ a: \"\" }]\n    },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n\n  return (\n    <form ref={form}>\n      <FieldGroup\n        name=\"foo\"\n        onUpdate={() => setValue(\"foo\", \"🍎\")}\n        onClear={() => setValue(\"foo\")}\n      />\n      <FieldGroup\n        name=\"bar[0]\"\n        onUpdate={() => setValue(\"bar[0]\", \"🍋\")}\n        onClear={() => setValue(\"bar[0]\")}\n      />\n      <FieldGroup\n        name=\"baz.a\"\n        onUpdate={() => setValue(\"baz.a\", \"🍉\")}\n        onClear={() => setValue(\"baz.a\")}\n      />\n      <FieldGroup\n        name=\"qux[0].a\"\n        onUpdate={() => setValue(\"qux[0].a\", \"🥝\")}\n        onClear={() => setValue(\"qux[0].a\")}\n      />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/complex-structures/package.json",
    "content": "{\n  \"name\": \"rcf-complex-structures\",\n  \"description\": \"The complex structures example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.1\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.1\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/complex-structures/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 3rem auto 0;\n  width: 24rem;\n\n  input,\n  button {\n    margin: 0.5rem 0;\n    padding: 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  > div {\n    display: flex;\n    justify-content: space-between;\n    margin-bottom: 1rem;\n\n    button {\n      width: 11.5rem;\n      border: 1px solid #fff;\n      color: #fff;\n      background: transparent;\n      cursor: pointer;\n    }\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/conditional-fields/index.js",
    "content": "import { useState } from \"react\";\nimport { render } from \"react-dom\";\nimport { useForm, useControlled, useFieldArray } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst RadioButtons = ({ name, buttons }) => {\n  const [fieldProps] = useControlled(name, {\n    defaultValue: buttons.filter(({ checked }) => checked)[0]?.value,\n    type: \"radio\"\n  });\n\n  return buttons.map(({ id, value, checked }) => (\n    <span key={id}>\n      <input {...fieldProps} id={id} value={value} defaultChecked={checked} />\n      <label htmlFor={id}>{value}</label>\n    </span>\n  ));\n};\n\nconst FieldArray = ({ name, notes }) => {\n  const [fields] = useFieldArray(name, {\n    defaultValue: notes\n  });\n\n  return fields.map((fieldName) => (\n    <input key={fieldName} name={`${fieldName}.text`} />\n  ));\n};\n\nfunction App() {\n  const { form } = useForm({\n    defaultValues: { username: \"\", email: \"\" },\n    // excludeFields: [\"more\"], // You can also exclude the field here by passing in name/id/class\n    // removeOnUnmounted: false, // To maintain the state of the unmouned fields (default = true)\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n  const [toggle, setToggle] = useState(false);\n\n  return (\n    <form ref={form}>\n      <input name=\"username\" placeholder=\"Username\" />\n      <input name=\"email\" type=\"email\" placeholder=\"Email\" />\n      <div>\n        <input\n          id=\"more\"\n          name=\"more\" // Used by the \"excludeFields\" option\n          type=\"checkbox\"\n          onChange={() => setToggle(!toggle)}\n          data-rcf-exclude // Exclude the fields via the pre-defined data attribute\n        />\n        <label htmlFor=\"more\">More</label>\n      </div>\n      {toggle && (\n        <>\n          <input\n            id=\"apple\"\n            name=\"fruit\"\n            type=\"radio\"\n            value=\"🍎\"\n            defaultChecked // Set default check (or value)\n          />\n          <label htmlFor=\"apple\">🍎</label>\n          <input id=\"kiwi\" name=\"fruit\" type=\"radio\" value=\"🥝\" />\n          <label htmlFor=\"kiwi\">🥝</label>\n          <input id=\"lemon\" name=\"fruit\" type=\"radio\" value=\"🍋\" />\n          <label htmlFor=\"lemon\">🍋</label>\n          {/* When working with conditional fields, please ensure the \"useControlled\" hook is wrapped in a component */}\n          {/* <RadioButtons\n            name=\"fruit\"\n            buttons={[\n              { id: \"apple\", value: \"🍎\", checked: true },\n              { id: \"kiwi\", value: \"🥝\" },\n              { id: \"lemon\", value: \"🍋\" }\n            ]}\n          /> */}\n          {/* When working with conditional fields, please ensure the \"useFieldArray\" hook is wrapped in a component */}\n          <FieldArray name=\"note\" notes={[{ text: \"\" }]} />\n        </>\n      )}\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/conditional-fields/package.json",
    "content": "{\n  \"name\": \"rcf-conditional-fields\",\n  \"description\": \"The conditional fields example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/conditional-fields/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  input:not([type=\"checkbox\"]):not([type=\"radio\"]) {\n    margin-bottom: 1.5rem;\n    padding: 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[name=\"note\"] {\n    margin-bottom: 0;\n  }\n\n  input[type=\"checkbox\"],\n  input[type=\"radio\"] {\n    margin-right: 0.5rem;\n    margin-bottom: 1rem;\n  }\n\n  label {\n    color: #fff;\n    margin-right: 1rem;\n  }\n\n  input[type=\"submit\"] {\n    margin-top: 0.5rem;\n    height: 2.5rem !important;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/custom-field/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm, useFormState, useFormMethods } from \"react-cool-form\";\nimport { TextField, Button } from \"@material-ui/core\";\n\nimport \"./styles.scss\";\n\nconst Field = ({ as, name, onChange, onBlur, ...restProps }) => {\n  const value = useFormState(`values.${name}`);\n  const { setValue, setTouched } = useFormMethods();\n  const Component = as;\n\n  return (\n    <Component\n      name={name}\n      value={value}\n      onChange={(e) => {\n        setValue(name, e.target.value); // Update the field's value and set it as touched\n        if (onChange) onChange(e);\n      }}\n      onBlur={(e) => {\n        setTouched(name); // Set the field as touched for displaying error (if it's not touched)\n        if (onBlur) onBlur(e);\n      }}\n      {...restProps}\n    />\n  );\n};\n\nfunction App() {\n  const { form, use } = useForm({\n    defaultValues: { username: \"\" },\n    // excludeFields: [\"username\"], // You can also exclude the field here\n    validate: ({ username }) => {\n      const errors = {};\n      if (!username.length) errors.username = \"Required\";\n      return errors;\n    },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n  const errors = use(\"errors\");\n\n  return (\n    <form ref={form} noValidate>\n      <Field\n        as={TextField}\n        label=\"Username\"\n        name=\"username\" // Used for the \"excludeFields\" option\n        required\n        error={!!errors.username}\n        helperText={errors.username}\n        inputProps={{ \"data-rcf-exclude\": true }} // Exclude the field via the pre-defined data attribute\n      />\n      <Button type=\"submit\" variant=\"contained\" color=\"primary\">\n        Submit\n      </Button>\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/custom-field/package.json",
    "content": "{\n  \"name\": \"rcf-custom-field\",\n  \"description\": \"The custom field example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"@material-ui/core\": \"^4.11.4\",\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/custom-field/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #fff;\n}\n\nform {\n  margin: 3rem auto 0;\n  width: 24rem;\n\n  .MuiFormControl-root,\n  .MuiTextField-root,\n  .MuiButton-root {\n    width: inherit;\n  }\n\n  .MuiFormControl-root,\n  .MuiFormControlLabel-root,\n  .MuiTextField-root {\n    margin-bottom: 1rem;\n  }\n}\n"
  },
  {
    "path": "examples/field-level-validation/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst validateOnServer = async (username) => {\n  await new Promise((r) => setTimeout(r, 2000));\n  return username === \"Welly\";\n};\n\nconst validateEmail = (value) => {\n  if (!value) {\n    return \"Required\";\n  } else if (!/^[A-Z0-9._-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$/i.test(value)) {\n    return \"Invalid email address\";\n  }\n};\n\nconst validateUsername = async (value) => {\n  if (!value) {\n    return \"Required\";\n  } else {\n    const hasUser = await validateOnServer(value);\n    if (!hasUser) return \"User doesn't exist\";\n  }\n};\n\nfunction App() {\n  const { form, field, use } = useForm({\n    defaultValues: { username: \"\", email: \"\" },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2)),\n    onError: (errors) => console.log(\"onError: \", errors)\n  });\n\n  console.log(\"Form is validating: \", use(\"isValidating\"));\n\n  return (\n    <form ref={form} noValidate>\n      <input\n        name=\"username\"\n        placeholder=\"Username\"\n        ref={field(validateUsername)}\n      />\n      <input\n        name=\"email\"\n        type=\"email\"\n        placeholder=\"Email\"\n        ref={field(validateEmail)}\n      />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/field-level-validation/package.json",
    "content": "{\n  \"name\": \"rcf-field-level-validation\",\n  \"description\": \"The field-level validation example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/field-level-validation/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  input {\n    margin-bottom: 1.5rem;\n    padding: 0 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/form-level-validation/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst validateOnServer = async (username) => {\n  await new Promise((r) => setTimeout(r, 2000));\n  return username === \"Welly\";\n};\n\nconst validate = async ({ username, email }) => {\n  const errors = {};\n\n  if (!username) {\n    errors.username = \"Required\";\n  } else {\n    const hasUser = await validateOnServer(username);\n    if (!hasUser) errors.username = \"User doesn't exist\";\n  }\n\n  if (!email.length) {\n    errors.email = \"Required\";\n  } else if (!/^[A-Z0-9._-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$/i.test(email)) {\n    errors.email = \"Invalid email address\";\n  }\n\n  return errors;\n};\n\nfunction App() {\n  const { form, use } = useForm({\n    defaultValues: { username: \"\", email: \"\" },\n    validate,\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2)),\n    onError: (errors) => console.log(\"onError: \", errors)\n  });\n\n  console.log(\"Form is validating: \", use(\"isValidating\"));\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" placeholder=\"Username\" />\n      <input name=\"email\" type=\"email\" placeholder=\"Email\" />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/form-level-validation/package.json",
    "content": "{\n  \"name\": \"rcf-form-level-validation\",\n  \"description\": \"The form-level validation example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/form-level-validation/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  input {\n    margin-bottom: 1.5rem;\n    padding: 0 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/form-submission/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst submitHandler = async (values) => {\n  await new Promise((r) => setTimeout(r, 2000));\n  alert(JSON.stringify(values, undefined, 2));\n};\n\nconst errorHandler = (errors) => console.log(\"onError: \", errors);\n\nfunction App() {\n  const { form, use } = useForm({\n    defaultValues: { username: \"\", email: \"\" },\n    onSubmit: submitHandler,\n    onError: errorHandler\n  });\n  const isSubmitting = use(\"isSubmitting\");\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" placeholder=\"Username\" required />\n      <input name=\"email\" type=\"email\" placeholder=\"Email\" required />\n      <input type=\"submit\" disabled={isSubmitting} />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/form-submission/package.json",
    "content": "{\n  \"name\": \"rcf-form-submission\",\n  \"description\": \"The form submission example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/form-submission/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  input {\n    margin-bottom: 1.5rem;\n    padding: 0 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/isolating-rerendering/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm, useFormState } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst checkStrength = (pwd) => {\n  const passed = [/[$@$!%*#?&]/, /[A-Z]/, /[0-9]/, /[a-z]/].reduce(\n    (cal, test) => cal + test.test(pwd),\n    0\n  );\n\n  return { 1: \"Weak\", 2: \"Good\", 3: \"Strong\", 4: \"Very strong\" }[passed];\n};\n\nconst FieldMessage = () => {\n  // Supports single-value-pick, array-pick, and object-pick data formats\n  const [error, value] = useFormState([\"errors.password\", \"values.password\"], {\n    formId: \"form-1\" // Provide the corresponding ID of the \"useForm\" hook\n  });\n\n  return <p>{error || checkStrength(value)}</p>;\n};\n\nfunction App() {\n  const { form } = useForm({\n    id: \"form-1\", // The ID is used by the \"useFormState\" hook\n    defaultValues: { password: \"\" },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <label htmlFor=\"password\">Password</label>\n      <input\n        id=\"password\"\n        name=\"password\"\n        type=\"password\"\n        required\n        minLength={8}\n      />\n      <FieldMessage />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/isolating-rerendering/package.json",
    "content": "{\n  \"name\": \"rcf-isolating-re-rendering\",\n  \"description\": \"The isolating re-rendering example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/isolating-rerendering/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  label {\n    display: block;\n    color: #fff;\n  }\n\n  input {\n    margin: 0.5rem 0;\n    padding: 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n\n  p {\n    margin: 0 0 1rem;\n    color: #ff9900;\n  }\n}\n"
  },
  {
    "path": "examples/joi/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm, set } from \"react-cool-form\";\nimport Joi from \"joi\";\n\nimport \"./styles.scss\";\n\nconst schema = Joi.object({\n  username: Joi.string().required(),\n  email: Joi.string().email({ tlds: false }).required(),\n  password: Joi.string().required().min(6)\n});\n\nconst validate = (values) => {\n  let errors = {};\n\n  const { error: joiError } = schema.validate(values, { abortEarly: false });\n\n  if (joiError)\n    joiError.details.forEach(({ path, message }) =>\n      set(errors, path[0], message)\n    );\n\n  return errors;\n};\n\nfunction App() {\n  const { form } = useForm({\n    defaultValues: { username: \"\", email: \"\", password: \"\" },\n    validate,\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2)),\n    onError: (errors) => console.log(\"onError: \", errors)\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" placeholder=\"Username\" />\n      <input name=\"email\" type=\"email\" placeholder=\"Email\" />\n      <input name=\"password\" type=\"password\" placeholder=\"Password\" />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/joi/package.json",
    "content": "{\n  \"name\": \"rcf-joi\",\n  \"version\": \"0.0.0\",\n  \"description\": \"The Joi example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"joi\": \"^17.4.0\",\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/joi/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  input {\n    margin-bottom: 1.5rem;\n    padding: 0 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/lazy-default-values/index.js",
    "content": "import { useEffect } from \"react\";\nimport { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst Field = ({ label, id, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n  </div>\n);\n\nfunction App() {\n  const { form, reset } = useForm({\n    onReset: (values) => console.log(\"onReset: \", values)\n  });\n\n  useEffect(() => reset({ firstName: \"Welly\", lastName: \"Shen\" }), [reset]);\n\n  return (\n    <form ref={form}>\n      <Field label=\"First Name\" id=\"first-name\" name=\"firstName\" />\n      <Field label=\"Last Name\" id=\"last-name\" name=\"lastName\" />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/lazy-default-values/package.json",
    "content": "{\n  \"name\": \"rcf-lazy-default-values\",\n  \"version\": \"0.0.0\",\n  \"description\": \"The lazy default values example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/lazy-default-values/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  div {\n    width: inherit;\n    margin-bottom: 1rem;\n  }\n\n  label {\n    display: block;\n    color: #fff;\n  }\n\n  input {\n    margin: 0.5rem 0;\n    padding: 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/material-ui/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\nimport {\n  FormGroup,\n  FormControl,\n  FormControlLabel,\n  FormLabel,\n  InputLabel,\n  TextField,\n  Select,\n  Checkbox,\n  RadioGroup,\n  Radio,\n  Button\n} from \"@material-ui/core\";\n\nimport \"./styles.scss\";\n\nfunction App() {\n  const { form, use } = useForm({\n    defaultValues: { username: \"\", framework: \"\", fruit: [], mood: \"\" },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n  const errors = use(\"errors\");\n\n  return (\n    <form ref={form} noValidate>\n      <TextField\n        label=\"Username\"\n        name=\"username\"\n        required\n        error={!!errors.username}\n        helperText={errors.username}\n      />\n      <FormControl>\n        <InputLabel htmlFor=\"framework\">Framework</InputLabel>\n        {/* When working with select, we need to enable the native use element or you can use the \"NativeSelect\" instead */}\n        <Select inputProps={{ id: \"framework\", name: \"framework\" }} native>\n          <option aria-label=\"None\" value=\"\" />\n          <option value=\"react\">React</option>\n          <option value=\"vue\">Vue</option>\n          <option value=\"angular\">Angular</option>\n          <option value=\"svelte\">Svelte</option>\n        </Select>\n      </FormControl>\n      <FormControl component=\"fieldset\">\n        <FormLabel component=\"legend\">Fruit</FormLabel>\n        <FormGroup row>\n          <FormControlLabel\n            control={<Checkbox />}\n            name=\"fruit\"\n            value=\"🍎\"\n            label=\"🍎\"\n          />\n          <FormControlLabel\n            control={<Checkbox />}\n            name=\"fruit\"\n            value=\"🍋\"\n            label=\"🍋\"\n          />\n          <FormControlLabel\n            control={<Checkbox />}\n            name=\"fruit\"\n            value=\"🥝\"\n            label=\"🥝\"\n          />\n        </FormGroup>\n      </FormControl>\n      <FormControl component=\"fieldset\">\n        <FormLabel component=\"legend\">Mood</FormLabel>\n        <RadioGroup name=\"mood\" aria-label=\"mood\" row>\n          <FormControlLabel control={<Radio />} value=\"😊\" label=\"😊\" />\n          <FormControlLabel control={<Radio />} value=\"🤬\" label=\"🤬\" />\n          <FormControlLabel control={<Radio />} value=\"😭\" label=\"😭\" />\n          <FormControlLabel control={<Radio />} value=\"🤣\" label=\"🤣\" />\n        </RadioGroup>\n      </FormControl>\n      <Button type=\"submit\" variant=\"contained\" color=\"primary\">\n        Submit\n      </Button>\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/material-ui/package.json",
    "content": "{\n  \"name\": \"rcf-material-ui\",\n  \"description\": \"The material-ui example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"@material-ui/core\": \"^4.11.4\",\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/material-ui/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #fff;\n}\n\nform {\n  margin: 3rem auto 0;\n  width: 24rem;\n\n  .MuiFormControl-root,\n  .MuiTextField-root,\n  .MuiButton-root {\n    width: inherit;\n  }\n\n  .MuiFormControl-root,\n  .MuiFormControlLabel-root,\n  .MuiTextField-root {\n    margin-bottom: 1rem;\n  }\n\n  .MuiFormControl-root:nth-child(2) {\n    margin-bottom: 1.5rem;\n  }\n\n  .MuiFormGroup-root .MuiFormControlLabel-root {\n    margin-bottom: 0;\n  }\n}\n"
  },
  {
    "path": "examples/multi-select/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nfunction App() {\n  const { form } = useForm({\n    defaultValues: { frameworks: [\"react\"] },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n\n  return (\n    <form ref={form}>\n      <label htmlFor=\"frameworks\">Frameworks</label>\n      <select id=\"frameworks\" name=\"frameworks\" multiple>\n        <option value=\"react\">React</option>\n        <option value=\"vue\">Vue</option>\n        <option value=\"angular\">Angular</option>\n        <option value=\"svelte\">Svelte</option>\n      </select>\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/multi-select/package.json",
    "content": "{\n  \"name\": \"rcf-multi-select\",\n  \"description\": \"The multi-select example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/multi-select/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  label {\n    display: block;\n    color: #fff;\n  }\n\n  input,\n  select {\n    margin: 0.5rem 0 1rem;\n    padding: 0.5rem;\n    width: inherit;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  select {\n    height: 6rem;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/quick-start/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst Field = ({ label, id, error, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n    {error && <p>{error}</p>}\n  </div>\n);\n\nfunction App() {\n  const { form, use } = useForm({\n    // (Strongly advise) Provide the default values just like we use React state\n    defaultValues: { username: \"\", email: \"\", password: \"\" },\n    // The event only triggered when the form is valid\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n  // We can enable the \"errorWithTouched\" option to filter the error of an un-blurred field\n  // Which helps the user focus on typing without being annoyed by the error message\n  const errors = use(\"errors\", { errorWithTouched: true });\n\n  return (\n    <form ref={form} noValidate>\n      <Field\n        label=\"Username\"\n        id=\"username\"\n        name=\"username\"\n        // Support built-in validation\n        required\n        error={errors.username}\n      />\n      <Field\n        label=\"Email\"\n        id=\"email\"\n        name=\"email\"\n        type=\"email\"\n        required\n        error={errors.email}\n      />\n      <Field\n        label=\"Password\"\n        id=\"password\"\n        name=\"password\"\n        type=\"password\"\n        required\n        minLength={8}\n        error={errors.password}\n      />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/quick-start/package.json",
    "content": "{\n  \"name\": \"rcf-quick-start\",\n  \"description\": \"The quick start of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/quick-start/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  div {\n    width: inherit;\n    margin-bottom: 1rem;\n  }\n\n  label {\n    display: block;\n    color: #fff;\n  }\n\n  input {\n    margin: 0.5rem 0;\n    padding: 0 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n\n  p {\n    margin: 0;\n    color: #ff9900;\n  }\n}\n"
  },
  {
    "path": "examples/radio-group/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst Field = ({ label, id, ...rest }) => (\n  <>\n    <input id={id} {...rest} />\n    <label htmlFor={id}>{label}</label>\n  </>\n);\n\nfunction App() {\n  const { form } = useForm({\n    defaultValues: { fruit: \"🍎\" },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n\n  return (\n    <form ref={form}>\n      <fieldset>\n        <legend>Fruit</legend>\n        <Field label=\"🍎\" id=\"apple\" name=\"fruit\" value=\"🍎\" type=\"radio\" />\n        <Field label=\"🍋\" id=\"lemon\" name=\"fruit\" value=\"🍋\" type=\"radio\" />\n        <Field label=\"🥝\" id=\"kiwi\" name=\"fruit\" value=\"🥝\" type=\"radio\" />\n      </fieldset>\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/radio-group/package.json",
    "content": "{\n  \"name\": \"rcf-radio-group\",\n  \"description\": \"The radio group example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/radio-group/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n  color: #fff;\n\n  fieldset {\n    margin-bottom: 2rem;\n    border-radius: 4px;\n    border-color: #555;\n  }\n\n  input {\n    margin-right: 0.5rem;\n\n    &:not(:first-of-type) {\n      margin-left: 1.5rem;\n    }\n  }\n\n  input[type=\"submit\"] {\n    width: inherit;\n    height: 2.5rem;\n    border: none;\n    border-radius: 4px;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/react-select/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm, useControlled } from \"react-cool-form\";\nimport Select from \"react-select\";\n\nimport \"./styles.scss\";\n\nconst Field = ({ as, name, ...restProps }) => {\n  const [fieldProps] = useControlled(name, restProps);\n  const Component = as;\n\n  return <Component {...fieldProps} />;\n};\n\nconst options = [\n  { label: \"React\", value: \"react\" },\n  { label: \"Vue\", value: \"vue\" },\n  { label: \"Angular\", value: \"angular\" },\n  { label: \"Svelte\", value: \"svelte\" }\n];\n\nfunction App() {\n  const { form } = useForm({\n    defaultValues: { framework: \"\" }, // We must provide a default value for the controlled field\n    excludeFields: [\"#framework\"], // Exclude the internal input element of React-Select by ID\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n\n  return (\n    <form ref={form}>\n      <Field\n        as={Select}\n        name=\"framework\"\n        inputId=\"framework\" // Used for excluding the internal input element of React-Select\n        options={options}\n        parse={(option) => option.value}\n        format={(value) => options.find((option) => option.value === value)}\n      />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/react-select/package.json",
    "content": "{\n  \"name\": \"rcf-react-select\",\n  \"description\": \"The react select example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\",\n    \"react-select\": \"^4.3.1\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/react-select/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  input[type=\"submit\"] {\n    margin-top: 1.5rem;\n    width: inherit;\n    height: 2.5rem;\n    font-size: 1rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/reset-form/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst Field = ({ label, id, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n  </div>\n);\n\nfunction App() {\n  const { form } = useForm({\n    defaultValues: { firstName: \"Welly\", lastName: \"Shen\" },\n    onSubmit: (values, { reset }) => reset(),\n    onReset: (values) => console.log(\"onReset: \", values)\n  });\n\n  return (\n    <form ref={form}>\n      <Field label=\"First Name\" id=\"first-name\" name=\"firstName\" />\n      <Field label=\"Last Name\" id=\"last-name\" name=\"lastName\" />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/reset-form/package.json",
    "content": "{\n  \"name\": \"rcf-reset-form\",\n  \"description\": \"The reset form example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/reset-form/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  div {\n    width: inherit;\n    margin-bottom: 1rem;\n  }\n\n  label {\n    display: block;\n    color: #fff;\n  }\n\n  input {\n    margin: 0.5rem 0;\n    padding: 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/showbox/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nlet count = 0;\n\nfunction App() {\n  count++;\n\n  const { form, use } = useForm({\n    defaultValues: { firstName: \"\", lastName: \"\", framework: \"\" },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n  const errors = use(\"errors\");\n\n  return (\n    <form ref={form} noValidate>\n      <div className=\"count\">Render {count} times</div>\n      <div>\n        <input name=\"firstName\" placeholder=\"First name\" required />\n        {errors.firstName && <p>{errors.firstName}</p>}\n      </div>\n      <div>\n        <input name=\"lastName\" placeholder=\"Last name\" required />\n        {errors.lastName && <p>{errors.lastName}</p>}\n      </div>\n      <select name=\"framework\">\n        <option value=\"\">I'm interesting in...</option>\n        <option value=\"react\">React</option>\n        <option value=\"vue\">Vue</option>\n        <option value=\"angular\">Angular</option>\n        <option value=\"svelte\">Svelte</option>\n      </select>\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/showbox/package.json",
    "content": "{\n  \"name\": \"rcf-showbox\",\n  \"description\": \"The showbox of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/showbox/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  .count {\n    padding: 0.25rem 0;\n    text-align: center;\n    color: #fff;\n    background: #333;\n    border-radius: 4px;\n  }\n\n  div,\n  select {\n    margin-bottom: 1.5rem;\n    width: inherit;\n  }\n\n  input,\n  select {\n    padding: 0 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border-radius: 4px;\n    border: none;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n\n  p {\n    margin-top: 0.5rem;\n    color: #ff9900;\n  }\n}\n"
  },
  {
    "path": "examples/typescript/index.tsx",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\ninterface FormValues {\n  firstName: string;\n  lastName: string;\n}\n\nfunction App() {\n  const { form } = useForm<FormValues>({\n    defaultValues: {\n      firstName: \"Welly\",\n      lastName: true // ❌ Type \"boolean\" is not assignable to type \"string\"\n    },\n    onSubmit: (values) => {\n      console.log(\"First Name: \", values.firstName);\n      console.log(\"Middle Name: \", values.middleName); // ❌ Property \"middleName\" does not exist on type \"FormValues\"\n    }\n  });\n\n  return (\n    <form ref={form}>\n      <input name=\"firstName\" />\n      <input name=\"lastName\" />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/typescript/package.json",
    "content": "{\n  \"name\": \"rcf-typescript\",\n  \"description\": \"The typescript example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.2\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/typescript/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  input {\n    margin-bottom: 1.5rem;\n    padding: 0 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "examples/without-form-element/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm } from \"react-cool-form\";\n\nimport \"./styles.scss\";\n\nconst Field = ({ label, id, error, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n    {error && <p>{error}</p>}\n  </div>\n);\n\nfunction App() {\n  const { form, use, submit } = useForm({\n    defaultValues: { email: \"\", password: \"\" },\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2))\n  });\n  const errors = use(\"errors\", { errorWithTouched: true });\n\n  return (\n    <div ref={form}>\n      <Field\n        label=\"Email\"\n        id=\"email\"\n        name=\"email\"\n        type=\"email\"\n        required\n        error={errors.email}\n      />\n      <Field\n        label=\"Password\"\n        id=\"password\"\n        name=\"password\"\n        type=\"password\"\n        required\n        minLength={8}\n        error={errors.password}\n      />\n      <button onClick={submit}>Submit</button>\n    </div>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/without-form-element/package.json",
    "content": "{\n  \"name\": \"rcf-without-form-element\",\n  \"description\": \"The without form element example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/without-form-element/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n\n  > div {\n    margin: 5rem auto 0;\n    width: 24rem;\n  \n    div {\n      width: inherit;\n      margin-bottom: 1rem;\n    }\n  \n    label {\n      display: block;\n      color: #fff;\n    }\n  \n    input,\n    button {\n      margin: 0.5rem 0;\n      padding: 0 0.5rem;\n      width: inherit;\n      height: 2rem;\n      border: none;\n      border-radius: 4px;\n      box-sizing: border-box;\n    }\n  \n    button {\n      height: 2.5rem;\n      font-size: 1rem;\n      color: #fff;\n      background: #0971f1;\n      cursor: pointer;\n    }\n  \n    p {\n      margin: 0;\n      color: #ff9900;\n    }\n  }  \n}\n\n"
  },
  {
    "path": "examples/wizard-form/.codesandbox/workspace.json",
    "content": "{\n  \"responsive-preview\": {\n    \"Mobile\": [\n      320,\n      675\n    ],\n    \"Tablet\": [\n      1024,\n      765\n    ],\n    \"Desktop\": [\n      1400,\n      800\n    ],\n    \"Desktop HD\": [\n      1920,\n      1080\n    ]\n  }\n}"
  },
  {
    "path": "examples/wizard-form/Step1.js",
    "content": "import { useForm } from \"react-cool-form\";\nimport { useNavigate } from \"react-router-dom\";\n\nimport { useFormValues } from \"./formValues\";\n\nconst Field = ({ label, id, error, ...rest }) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <input id={id} {...rest} />\n    {error && <p>{error}</p>}\n  </div>\n);\n\nconst Step1 = () => {\n  const [formValues, setFormValues] = useFormValues();\n  const nav = useNavigate();\n  const { form, use, submit } = useForm({\n    // Fill in form values from context\n    defaultValues: formValues,\n    // Pass form values for other steps via context\n    onSubmit: (values) => {\n      setFormValues(values);\n      nav(\"/step-2\");\n    }\n  });\n  // Show error message only when the field is touched\n  const [errors, values] = use([\"errors\", \"values\"], {\n    errorWithTouched: true\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <Field id=\"name\" label=\"Name\" name=\"name\" required error={errors.name} />\n      <Field\n        id=\"email\"\n        label=\"Email\"\n        name=\"email\"\n        type=\"email\"\n        required\n        error={errors.email}\n      />\n      <div className=\"btn\">\n        <button type=\"button\" onClick={submit}>\n          Next\n        </button>\n      </div>\n      <pre>{JSON.stringify(values, undefined, 2)}</pre>\n    </form>\n  );\n};\n\nexport default Step1;\n"
  },
  {
    "path": "examples/wizard-form/Step2.js",
    "content": "import { forwardRef } from \"react\";\nimport { useForm } from \"react-cool-form\";\nimport { useNavigate, Link } from \"react-router-dom\";\n\nimport { useFormValues } from \"./formValues\";\n\nconst Select = forwardRef(({ label, id, children, error, ...rest }, ref) => (\n  <div>\n    <label htmlFor={id}>{label}</label>\n    <select id={id} ref={ref} {...rest}>\n      {children}\n    </select>\n    {error && <p>{error}</p>}\n  </div>\n));\n\nconst Step2 = () => {\n  const [formValues, setFormValues] = useFormValues();\n  const nav = useNavigate();\n  const { form, use, field, submit } = useForm({\n    // Fill in form values from context\n    defaultValues: { sports: [\"football\"], ...formValues },\n    // Pass form values for other steps via context\n    onSubmit: (values) => {\n      setFormValues(values);\n      nav(\"/step-3\");\n    }\n  });\n  const [errors, values] = use([\"errors\", \"values\"], {\n    errorWithTouched: true\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <Select\n        id=\"sports\"\n        label=\"Sports\"\n        name=\"sports\"\n        multiple\n        ref={field((value) => {\n          if (!value.length) return \"Required\";\n          return value.length < 2 ? \"Choose more\" : false;\n        })}\n        error={errors.sports}\n      >\n        <option value=\"football\">🏈</option>\n        <option value=\"soccer\">⚽️</option>\n        <option value=\"basketball\">🏀</option>\n        <option value=\"baseball\">⚾️</option>\n        <option value=\"tennis\">🎾</option>\n        <option value=\"volleyball\">🏐</option>\n      </Select>\n      <div className=\"btn\">\n        <Link to=\"/\">Previous</Link>\n        <button id=\"step-2\" type=\"button\" onClick={submit}>\n          Next\n        </button>\n      </div>\n      <pre>{JSON.stringify(values, undefined, 2)}</pre>\n    </form>\n  );\n};\n\nexport default Step2;\n"
  },
  {
    "path": "examples/wizard-form/Step3.js",
    "content": "import { useState } from \"react\";\nimport { useForm } from \"react-cool-form\";\nimport { Link } from \"react-router-dom\";\n\nimport { useFormValues } from \"./formValues\";\n\nconst Checkbox = ({ id, label, ...rest }) => (\n  <label htmlFor={id}>\n    <input id={id} {...rest} /> {label}\n  </label>\n);\n\nconst Step3 = () => {\n  const [formValues, setFormValues] = useFormValues();\n  const [toggle, setToggle] = useState(!!formValues?.fruit?.length);\n  const { form, use } = useForm({\n    // Fill in form values from context\n    defaultValues: formValues,\n    validate: ({ fruit }) =>\n      fruit && !fruit.length ? { fruit: \"Required\" } : {},\n    onSubmit: (values) => {\n      // Pass form values for other steps via context\n      setFormValues(values);\n      alert(JSON.stringify(values, undefined, 2));\n    }\n  });\n  const [errors, values] = use([\"errors\", \"values\"]);\n\n  return (\n    <form ref={form} noValidate>\n      <div>\n        <label htmlFor=\"fruit\">\n          Fruit{\" \"}\n          <input\n            id=\"fruit\"\n            type=\"checkbox\"\n            defaultChecked={toggle}\n            onClick={() => setToggle(!toggle)}\n            // Exclude the toggler from form values\n            data-rcf-exclude\n          />\n        </label>\n      </div>\n      {toggle && (\n        <div className=\"fruit\">\n          <Checkbox\n            id=\"apple\"\n            label=\"🍎\"\n            name=\"fruit\"\n            type=\"checkbox\"\n            value=\"apple\"\n          />\n          <Checkbox\n            id=\"lemon\"\n            label=\"🍋\"\n            name=\"fruit\"\n            type=\"checkbox\"\n            value=\"lemon\"\n          />\n          <Checkbox\n            id=\"watermelon\"\n            label=\"🍉\"\n            name=\"fruit\"\n            type=\"checkbox\"\n            value=\"watermelon\"\n          />\n          <Checkbox\n            id=\"cherry\"\n            label=\"🍒\"\n            name=\"fruit\"\n            type=\"checkbox\"\n            value=\"cherry\"\n          />\n        </div>\n      )}\n      {errors.fruit && <p>{errors.fruit}</p>}\n      <div className=\"btn\">\n        <Link to=\"/step-2\">Previous</Link>\n        <input type=\"submit\" />\n      </div>\n      <pre>{JSON.stringify(values, undefined, 2)}</pre>\n    </form>\n  );\n};\n\nexport default Step3;\n"
  },
  {
    "path": "examples/wizard-form/formValues.js",
    "content": "import { createContext, useState, useContext } from \"react\";\n\nconst Context = createContext();\n\nconst FormValuesProvider = ({ children }) => {\n  const [formValues, setFormValues] = useState({});\n\n  return (\n    <Context.Provider value={[formValues, setFormValues]}>\n      {children}\n    </Context.Provider>\n  );\n};\n\nconst useFormValues = () => useContext(Context);\n\nexport { FormValuesProvider, useFormValues };\n"
  },
  {
    "path": "examples/wizard-form/index.js",
    "content": "import { render } from \"react-dom\";\nimport { BrowserRouter as Router, Routes, Route } from \"react-router-dom\";\n\nimport { FormValuesProvider } from \"./formValues\";\nimport Step1 from \"./Step1\";\nimport Step2 from \"./Step2\";\nimport Step3 from \"./Step3\";\n\nimport \"./styles.scss\";\n\nrender(\n  // Share form values for all the steps via Context API\n  <FormValuesProvider>\n    <Router>\n      <Routes>\n        <Route path=\"/\" element={<Step1 />} />\n        <Route path=\"step-2\" element={<Step2 />} />\n        <Route path=\"step-3\" element={<Step3 />} />\n      </Routes>\n    </Router>\n  </FormValuesProvider>,\n  document.getElementById(\"root\")\n);\n"
  },
  {
    "path": "examples/wizard-form/package.json",
    "content": "{\n  \"name\": \"rcf-wizard-form\",\n  \"description\": \"The wizard form example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"history\": \"^5.0.0\",\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router-dom\": \"next\",\n    \"react-scripts\": \"^4.0.3\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"]\n}\n"
  },
  {
    "path": "examples/wizard-form/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 3rem auto 0;\n  width: 24rem;\n\n  label {\n    display: block;\n    color: #fff;\n  }\n\n  p {\n    margin-top: -0.5rem;\n    color: #ff9900;\n  }\n\n  div {\n    width: inherit;\n    margin-bottom: 1rem;\n\n    p {\n      margin-top: 0;\n    }\n  }\n\n  input:not([type=\"checkbox\"]),\n  select,\n  button,\n  a {\n    margin: 0.5rem 0;\n    padding: 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  select {\n    height: 10rem;\n  }\n\n  input[type=\"submit\"],\n  button,\n  a {\n    width: 7rem;\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n\n  button,\n  a {\n    border: 1px solid #fff;\n    background: none;\n  }\n\n  button {\n    margin-left: auto;\n  }\n\n  a {\n    text-align: center;\n    text-decoration: none;\n  }\n\n  .fruit {\n    display: flex;\n\n    label {\n      margin-right: 1rem;\n    }\n  }\n\n  .btn {\n    display: flex;\n    justify-content: space-between;\n  }\n\n  pre {\n    margin-top: 5rem;\n    padding: 1rem;\n    border: 1px solid #fff;\n    border-radius: 4px;\n    color: #fff;\n    background: #000;\n  }\n}\n"
  },
  {
    "path": "examples/yup/index.js",
    "content": "import { render } from \"react-dom\";\nimport { useForm, set } from \"react-cool-form\";\nimport * as yup from \"yup\";\nimport Joi from \"joi\";\n\nimport \"./styles.scss\";\n\n// Reusable validation function for Yup\nconst validateWithYup = (schema) => async (values) => {\n  let errors = {};\n\n  try {\n    await schema.validate(values, { abortEarly: false });\n  } catch (yupError) {\n    yupError.inner.forEach(({ path, message }) => set(errors, path, message));\n  }\n\n  return errors;\n};\n\n// Reusable validation function for Joi\nconst validateWithJoi = (schema) => (values) => {\n  let errors = {};\n\n  const { error: joiError } = schema.validate(values, { abortEarly: false });\n\n  if (joiError)\n    joiError.details.forEach(({ path, message }) =>\n      set(errors, path[0], message)\n    );\n\n  return errors;\n};\n\nconst yupSchema = yup.object().shape({\n  username: yup.string().required(),\n  email: yup.string().email().required(),\n  password: yup.string().required().min(6)\n});\n\nconst JoiSchema = Joi.object({\n  username: Joi.string().required(),\n  email: Joi.string().email({ tlds: false }).required(),\n  password: Joi.string().required().min(6)\n});\n\nfunction App() {\n  const { form } = useForm({\n    defaultValues: { username: \"\", email: \"\", password: \"\" },\n    validate: validateWithYup(yupSchema),\n    // validate: validateWithJoi(JoiSchema),\n    onSubmit: (values) => alert(JSON.stringify(values, undefined, 2)),\n    onError: (errors) => console.log(\"onError: \", errors)\n  });\n\n  return (\n    <form ref={form} noValidate>\n      <input name=\"username\" placeholder=\"Username\" />\n      <input name=\"email\" type=\"email\" placeholder=\"Email\" />\n      <input name=\"password\" type=\"password\" placeholder=\"Password\" />\n      <input type=\"submit\" />\n    </form>\n  );\n}\n\nrender(<App />, document.getElementById(\"root\"));\n"
  },
  {
    "path": "examples/yup/package.json",
    "content": "{\n  \"name\": \"rcf-schema\",\n  \"description\": \"The schema example of RCF.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"joi\": \"^17.4.0\",\n    \"react\": \"^17.0.2\",\n    \"react-cool-form\": \"latest\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-scripts\": \"^4.0.3\",\n    \"yup\": \"^0.32.9\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"browserslist\": [\">0.2%\", \"not dead\", \"not ie <= 11\", \"not op_mini all\"],\n  \"keywords\": []\n}\n"
  },
  {
    "path": "examples/yup/styles.scss",
    "content": "body {\n  font-family: sans-serif;\n  background: #1a1a1a;\n}\n\nform {\n  margin: 5rem auto 0;\n  width: 24rem;\n\n  input {\n    margin-bottom: 1.5rem;\n    padding: 0 0.5rem;\n    width: inherit;\n    height: 2rem;\n    border: none;\n    border-radius: 4px;\n    box-sizing: border-box;\n  }\n\n  input[type=\"submit\"] {\n    height: 2.5rem;\n    font-size: 1rem;\n    color: #fff;\n    background: #0971f1;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-cool-form\",\n  \"version\": \"0.4.1\",\n  \"description\": \"React hooks for forms state and validation, less code more performant.\",\n  \"license\": \"MIT\",\n  \"homepage\": \"https://react-cool-form.netlify.app\",\n  \"repository\": \"https://github.com/wellyshen/react-cool-form\",\n  \"bugs\": \"https://github.com/wellyshen/react-cool-form/issues\",\n  \"keywords\": [\n    \"react\",\n    \"hooks\",\n    \"form\",\n    \"forms\",\n    \"form-builder\",\n    \"form-state\",\n    \"form-validation\",\n    \"state\",\n    \"state-management\",\n    \"validation\",\n    \"uncontrolled\",\n    \"controlled\",\n    \"arrays\",\n    \"lists\",\n    \"dx\",\n    \"ux\",\n    \"performance\",\n    \"react-hooks\",\n    \"asynchronous\",\n    \"typescript\"\n  ],\n  \"author\": \"Welly Shen <hivoid19@gmail.com> (https://github.com/wellyshen)\",\n  \"main\": \"dist/index.js\",\n  \"module\": \"dist/index.esm.js\",\n  \"umd:main\": \"dist/index.umd.production.min.js\",\n  \"unpkg\": \"dist/index.umd.production.min.js\",\n  \"types\": \"dist/index.d.ts\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"link-pkg\": \"yarn build:dev && npm link app/node_modules/react && yarn link\",\n    \"start\": \"yarn build:dev -w\",\n    \"build:dev\": \"yarn clean:build && yarn copy:type && rollup -c scripts/rollup/config.js\",\n    \"build:prod\": \"yarn clean:build && yarn clean:size && yarn copy && rollup -c scripts/rollup/config.js --environment BUILD:production\",\n    \"lint\": \"run-s lint:*\",\n    \"lint:code\": \"eslint --fix . --ext .js,.ts,.tsx\",\n    \"lint:type\": \"tsc\",\n    \"lint:format\": \"prettier -w . -u --loglevel silent\",\n    \"test\": \"jest --config scripts/jest/config.js\",\n    \"test:watch\": \"yarn test --watch\",\n    \"test:cov\": \"yarn clean:cov && yarn test --coverage\",\n    \"size\": \"yarn build:prod && bundlesize\",\n    \"clean\": \"run-p clean:*\",\n    \"clean:build\": \"rimraf dist\",\n    \"clean:size\": \"rimraf .size-snapshot.json\",\n    \"clean:cov\": \"rimraf coverage\",\n    \"copy\": \"run-p copy:*\",\n    \"copy:cjs\": \"cpy scripts/rollup/cjsEntryFile.js dist --rename=index.js\",\n    \"copy:type\": \"cpy src/types/react-cool-form.d.ts dist --rename=index.d.ts\",\n    \"release\": \"yarn build:prod && changeset publish\",\n    \"prepare\": \"husky install\"\n  },\n  \"lint-staged\": {\n    \"*.{js,ts,tsx}\": \"eslint --fix\",\n    \"**/*\": \"prettier -w -u\"\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.14.8\",\n    \"dequal\": \"^2.0.2\"\n  },\n  \"devDependencies\": {\n    \"@ampproject/rollup-plugin-closure-compiler\": \"^0.27.0\",\n    \"@babel/core\": \"^7.14.8\",\n    \"@babel/plugin-transform-runtime\": \"^7.14.5\",\n    \"@babel/preset-env\": \"^7.14.8\",\n    \"@babel/preset-react\": \"^7.14.5\",\n    \"@babel/preset-typescript\": \"^7.14.5\",\n    \"@changesets/changelog-github\": \"^0.4.0\",\n    \"@changesets/cli\": \"^2.16.0\",\n    \"@rollup/plugin-babel\": \"^5.3.0\",\n    \"@rollup/plugin-commonjs\": \"^19.0.1\",\n    \"@rollup/plugin-node-resolve\": \"^13.0.2\",\n    \"@rollup/plugin-replace\": \"^3.0.0\",\n    \"@testing-library/jest-dom\": \"^5.14.1\",\n    \"@testing-library/react\": \"^12.0.0\",\n    \"@testing-library/react-hooks\": \"^7.0.1\",\n    \"@testing-library/user-event\": \"^13.2.0\",\n    \"@types/jest\": \"^26.0.24\",\n    \"@types/react\": \"^17.0.14\",\n    \"bundlesize2\": \"^0.0.28\",\n    \"cpy-cli\": \"^3.1.1\",\n    \"eslint\": \"^7.2.0\",\n    \"eslint-config-welly\": \"^1.13.0\",\n    \"husky\": \"^7.0.1\",\n    \"jest\": \"^27.0.6\",\n    \"lint-staged\": \"^11.1.0\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"prettier\": \"^2.3.2\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-test-renderer\": \"^17.0.2\",\n    \"rimraf\": \"^3.0.2\",\n    \"rollup\": \"^2.53.3\",\n    \"rollup-plugin-size-snapshot\": \"^0.12.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\",\n    \"ts-jest\": \"^27.0.4\",\n    \"typescript\": \"^4.3.5\"\n  },\n  \"peerDependencies\": {\n    \"react\": \">= 16.8.0\"\n  }\n}\n"
  },
  {
    "path": "scripts/jest/config.js",
    "content": "module.exports = {\n  preset: \"ts-jest\",\n  rootDir: \"../../\",\n  testEnvironment: \"jsdom\",\n  setupFilesAfterEnv: [\"<rootDir>/scripts/jest/setup.ts\"],\n  collectCoverageFrom: [\"src/**/*.ts\", \"!**/index.ts\", \"!src/types/*\"],\n  globals: { __DEV__: true },\n};\n"
  },
  {
    "path": "scripts/jest/setup.ts",
    "content": "import \"@testing-library/jest-dom\";\n"
  },
  {
    "path": "scripts/rollup/cjsEntryFile.js",
    "content": "\"use strict\";\n\nmodule.exports =\n  process.env.NODE_ENV === \"production\"\n    ? require(\"./index.cjs.production.min.js\")\n    : require(\"./index.cjs.development.js\");\n"
  },
  {
    "path": "scripts/rollup/config.js",
    "content": "import createConfig from \"./createConfig\";\n\nconst isDev = process.env.BUILD !== \"production\";\nconst name = \"index\";\nconst umdName = \"ReactCoolForm\";\nconst options = [\n  {\n    name,\n    format: \"cjs\",\n    env: \"development\",\n  },\n  {\n    name,\n    format: \"cjs\",\n    env: \"production\",\n  },\n  {\n    name,\n    format: \"esm\",\n  },\n  {\n    name,\n    umdName,\n    format: \"umd\",\n    env: \"development\",\n  },\n  {\n    name,\n    umdName,\n    format: \"umd\",\n    env: \"production\",\n  },\n];\n\nexport default options\n  .filter(({ format }) => (isDev ? format === \"esm\" : true))\n  .map((option) => createConfig({ ...option, measure: !isDev }));\n"
  },
  {
    "path": "scripts/rollup/createConfig.js",
    "content": "import resolve from \"@rollup/plugin-node-resolve\";\nimport commonjs from \"@rollup/plugin-commonjs\";\nimport babel from \"@rollup/plugin-babel\";\nimport replace from \"@rollup/plugin-replace\";\nimport { sizeSnapshot } from \"rollup-plugin-size-snapshot\";\nimport compiler from \"@ampproject/rollup-plugin-closure-compiler\";\nimport { terser } from \"rollup-plugin-terser\";\n\nimport pkg from \"../../package.json\";\n\nconst babelRuntimeVersion = pkg.dependencies[\"@babel/runtime\"].replace(\n  /^[^0-9]*/,\n  \"\"\n);\n\nconst makeExternalPredicate = (external) =>\n  !external.length\n    ? () => false\n    : (id) => new RegExp(`^(${external.join(\"|\")})($|/)`).test(id);\n\nexport default ({ name, umdName, format, env, measure }) => {\n  const isUmd = format === \"umd\";\n  const shouldMinify = env === \"production\";\n  const extensions = [\".ts\"];\n  const fileName = [name, format, env, shouldMinify ? \"min\" : \"\", \"js\"]\n    .filter(Boolean)\n    .join(\".\");\n\n  return {\n    input: \"src\",\n    output: {\n      file: `${pkg.files[0]}/${fileName}`,\n      format,\n      name: umdName,\n      sourcemap: true,\n      globals: { react: \"React\" },\n      exports: \"named\",\n    },\n    plugins: [\n      resolve({ extensions }),\n      isUmd && commonjs(),\n      babel({\n        exclude: \"node_modules/**\",\n        plugins: [\n          [\n            \"@babel/plugin-transform-runtime\",\n            { version: babelRuntimeVersion, helpers: !isUmd },\n          ],\n        ],\n        babelHelpers: isUmd ? \"bundled\" : \"runtime\",\n        extensions,\n      }),\n      replace({\n        __DEV__: 'process.env.NODE_ENV !== \"production\"',\n        ...(env ? { \"process.env.NODE_ENV\": JSON.stringify(env) } : {}),\n      }),\n      measure && sizeSnapshot(),\n      shouldMinify &&\n        compiler({\n          formatting: \"PRETTY_PRINT\",\n          compilation_level: \"SIMPLE_OPTIMIZATIONS\",\n        }),\n      shouldMinify &&\n        terser({\n          output: { comments: false },\n          compress: { drop_console: true },\n        }),\n    ].filter(Boolean),\n    external: makeExternalPredicate([\n      ...Object.keys(pkg.peerDependencies),\n      ...(isUmd ? [] : Object.keys(pkg.dependencies)),\n    ]),\n  };\n};\n"
  },
  {
    "path": "src/hooks/index.ts",
    "content": "export { default as useState } from \"./useState\";\nexport { default as useLatest } from \"./useLatest\";\n"
  },
  {
    "path": "src/hooks/useLatest.test.ts",
    "content": "import { renderHook } from \"@testing-library/react-hooks\";\n\nimport useLatest from \"./useLatest\";\n\ndescribe(\"useLatest\", () => {\n  it(\"should return correctly\", () => {\n    const val = \"test\";\n    const { result } = renderHook(() => useLatest(val));\n    expect(result.current.current).toBe(val);\n  });\n});\n"
  },
  {
    "path": "src/hooks/useLatest.ts",
    "content": "import { MutableRefObject, useRef } from \"react\";\n\nexport default <T>(val: T): MutableRefObject<T> => {\n  const ref = useRef(val);\n  ref.current = val;\n  return ref;\n};\n"
  },
  {
    "path": "src/hooks/useState.test.ts",
    "content": "import { useReducer } from \"react\";\nimport { renderHook } from \"@testing-library/react-hooks\";\n\nimport useState from \"./useState\";\n\nconst forceUpdate = jest.fn();\n\njest.mock(\"react\", () => ({\n  ...(jest.requireActual(\"react\") as object),\n  useReducer: jest.fn(),\n}));\n(useReducer as jest.Mock).mockImplementation(() => [, forceUpdate]);\n\ndescribe(\"useState\", () => {\n  const initialState = {\n    values: { foo: \"🍋\" },\n    touched: {},\n    errors: {},\n    dirty: {},\n    isDirty: false,\n    isValidating: false,\n    isValid: true,\n    isSubmitting: false,\n    isSubmitted: false,\n    submitCount: 0,\n  };\n  const renderHelper = (onChange?: (state: any) => void) => {\n    const { observersRef, ...rest } = renderHook(() =>\n      useState(initialState, onChange)\n    ).result.current;\n\n    return { observer: observersRef.current[0], ...rest };\n  };\n\n  beforeEach(() => forceUpdate.mockClear());\n\n  it(\"should set initial state correctly\", () => {\n    const { stateRef } = renderHelper();\n    expect(stateRef.current).toEqual(initialState);\n  });\n\n  it(\"should set state and re-render correctly\", () => {\n    const { stateRef, setStateRef, observer } = renderHelper();\n    let state = {\n      ...initialState,\n      values: { foo: \"🍎\" },\n      touched: { foo: true },\n      errors: { foo: \"Required\" },\n      isDirty: true,\n      dirty: { foo: true },\n      isValid: false,\n      submitCount: 1,\n    };\n\n    setStateRef(\"\", state);\n    expect(stateRef.current).toEqual(state);\n    expect(forceUpdate).not.toHaveBeenCalled();\n\n    state = { ...state, values: { foo: \"🍋\" } };\n    observer.usedState = { values: true };\n    setStateRef(\"\", state);\n    expect(forceUpdate).toHaveBeenCalledTimes(1);\n\n    setStateRef(\"\", state);\n    expect(forceUpdate).toHaveBeenCalledTimes(1);\n  });\n\n  it(\"should set state without re-render\", () => {\n    const { setStateRef } = renderHelper();\n    setStateRef(\"\", initialState);\n    expect(forceUpdate).not.toHaveBeenCalled();\n  });\n\n  it(\"should set values without re-render\", () => {\n    const { stateRef, setStateRef } = renderHelper();\n    const foo = \"🍎\";\n    const error = \"Required\";\n    const isValidating = true;\n    const isSubmitting = true;\n    const isSubmitted = true;\n    setStateRef(\"values.foo\", foo);\n    setStateRef(\"touched.foo\", true);\n    setStateRef(\"errors.foo\", error);\n    setStateRef(\"dirty.foo\", true);\n    setStateRef(\"isValidating\", isValidating);\n    setStateRef(\"isSubmitting\", isSubmitting);\n    setStateRef(\"isSubmitted\", isSubmitted);\n    expect(forceUpdate).not.toHaveBeenCalled();\n    expect(stateRef.current).toEqual({\n      values: { foo },\n      touched: { foo: true },\n      errors: { foo: error },\n      isDirty: true,\n      dirty: { foo: true },\n      isValidating,\n      isValid: false,\n      isSubmitting,\n      isSubmitted,\n      submitCount: 1,\n    });\n  });\n\n  it(\"should set values and re-render correctly\", () => {\n    const { stateRef, setStateRef, observer } = renderHelper();\n\n    const value = \"🍎\";\n    observer.usedState = { \"values.foo\": true };\n    setStateRef(\"values.foo\", value);\n    setStateRef(\"values.foo\", value);\n    expect(forceUpdate).toHaveBeenCalledTimes(2);\n\n    observer.usedState = { \"touched.foo\": true };\n    setStateRef(\"touched.foo\", true);\n    setStateRef(\"touched.foo\", true);\n    expect(forceUpdate).toHaveBeenCalledTimes(3);\n\n    const error = \"Required\";\n    observer.usedState = { \"errors.foo\": true };\n    setStateRef(\"errors.foo\", error);\n    setStateRef(\"errors.foo\", error);\n    expect(forceUpdate).toHaveBeenCalledTimes(4);\n\n    observer.usedState = { \"dirty.foo\": true };\n    setStateRef(\"dirty.foo\", true);\n    setStateRef(\"dirty.foo\", true);\n    expect(forceUpdate).toHaveBeenCalledTimes(5);\n\n    const isValidating = true;\n    observer.usedState = { isValidating: true };\n    setStateRef(\"isValidating\", isValidating);\n    setStateRef(\"isValidating\", isValidating);\n    expect(forceUpdate).toHaveBeenCalledTimes(6);\n\n    const isSubmitting = true;\n    observer.usedState = { isSubmitting: true };\n    setStateRef(\"isSubmitting\", isSubmitting);\n    setStateRef(\"isSubmitting\", isSubmitting);\n    expect(forceUpdate).toHaveBeenCalledTimes(7);\n\n    const isSubmitted = true;\n    observer.usedState = { isSubmitted: true };\n    setStateRef(\"isSubmitted\", isSubmitted);\n    setStateRef(\"isSubmitted\", isSubmitted);\n    expect(forceUpdate).toHaveBeenCalledTimes(8);\n\n    expect(stateRef.current).toEqual({\n      values: { foo: value },\n      touched: { foo: true },\n      errors: { foo: error },\n      isDirty: true,\n      dirty: { foo: true },\n      isValidating,\n      isValid: false,\n      isSubmitting,\n      isSubmitted,\n      submitCount: 1,\n    });\n  });\n\n  it('should set \"isValid\", \"isDirty\", \"submitCount\" without re-render', () => {\n    const { setStateRef } = renderHelper();\n    setStateRef(\"errors\", { foo: \"Required\" });\n    setStateRef(\"dirty\", { foo: true });\n    setStateRef(\"isSubmitting\", true);\n    expect(forceUpdate).not.toHaveBeenCalled();\n  });\n\n  it('should set \"isValid\", \"isDirty\", \"submitCount\" and re-render correctly', () => {\n    const { setStateRef, observer } = renderHelper();\n\n    observer.usedState = { isValid: true };\n    setStateRef(\"errors\", { foo: \"Required\" });\n    setStateRef(\"errors\", { foo: \"Required\" });\n    expect(forceUpdate).toHaveBeenCalledTimes(1);\n\n    observer.usedState = { isDirty: true };\n    setStateRef(\"dirty\", { foo: true });\n    setStateRef(\"dirty\", { foo: true });\n    expect(forceUpdate).toHaveBeenCalledTimes(2);\n\n    observer.usedState = { submitCount: true };\n    setStateRef(\"isSubmitting\", true);\n    setStateRef(\"isSubmitting\", true);\n    expect(forceUpdate).toHaveBeenCalledTimes(3);\n  });\n\n  it(\"should re-render due to match parent path (parent = used-state)\", () => {\n    const { setStateRef, observer } = renderHelper();\n\n    observer.usedState = { values: true };\n    setStateRef(\"values.foo\", \"🍎\");\n    expect(forceUpdate).toHaveBeenCalledTimes(1);\n\n    observer.usedState = { touched: true };\n    setStateRef(\"touched.foo\", true);\n    expect(forceUpdate).toHaveBeenCalledTimes(2);\n\n    observer.usedState = { errors: true };\n    setStateRef(\"errors.foo\", \"Required\");\n    expect(forceUpdate).toHaveBeenCalledTimes(3);\n\n    observer.usedState = { dirty: true };\n    setStateRef(\"dirty.foo\", true);\n    expect(forceUpdate).toHaveBeenCalledTimes(4);\n  });\n\n  it(\"should re-render due to match parent path (parent = set-state)\", () => {\n    const { setStateRef, observer } = renderHelper();\n\n    observer.usedState = { \"values.foo\": true };\n    setStateRef(\"values\", { foo: \"🍎\" });\n    expect(forceUpdate).toHaveBeenCalledTimes(1);\n\n    observer.usedState = { \"touched.foo\": true };\n    setStateRef(\"touched.foo\", { foo: true });\n    expect(forceUpdate).toHaveBeenCalledTimes(2);\n\n    observer.usedState = { \"errors.foo\": true };\n    setStateRef(\"errors\", { foo: \"Required\" });\n    expect(forceUpdate).toHaveBeenCalledTimes(3);\n\n    observer.usedState = { \"dirty.foo\": true };\n    setStateRef(\"dirty\", { foo: true });\n    expect(forceUpdate).toHaveBeenCalledTimes(4);\n  });\n\n  it(\"should skip re-render\", () => {\n    const onChange = jest.fn();\n    const { setStateRef, observer } = renderHelper(onChange);\n    observer.usedState = { values: true };\n    setStateRef(\"values.foo\", \"🍎\", { shouldSkipUpdate: true });\n    expect(onChange).toHaveBeenCalled();\n    expect(forceUpdate).not.toHaveBeenCalled();\n  });\n\n  it(\"should force re-render\", () => {\n    const { setStateRef } = renderHelper();\n    setStateRef(\"values.foo\", \"🍎\", { shouldForceUpdate: true });\n    expect(forceUpdate).toHaveBeenCalled();\n  });\n\n  it('should re-render correctly based on \"fieldPath\"', () => {\n    const { setStateRef, observer } = renderHelper();\n    const fieldPath = \"values.some-value\";\n\n    observer.usedState = { [fieldPath]: true };\n    setStateRef(\"values.foo\", \"🍎\");\n    expect(forceUpdate).not.toHaveBeenCalled();\n\n    setStateRef(\"values.foo\", \"🍎\", { fieldPath });\n    expect(forceUpdate).toHaveBeenCalledTimes(1);\n  });\n\n  it('should trigger \"onChange\" correctly when setting state', () => {\n    const onChange = jest.fn();\n    const { setStateRef } = renderHelper(onChange);\n    const state = {\n      ...initialState,\n      values: { ...initialState.values, foo: \"🍎\" },\n    };\n    setStateRef(\"\", state);\n    setStateRef(\"\", state);\n    expect(onChange).toHaveBeenCalledTimes(1);\n    expect(onChange).toHaveBeenCalledWith(state);\n  });\n\n  it('should trigger \"onChange\" correctly when setting values', () => {\n    const onChange = jest.fn();\n    const { setStateRef } = renderHelper(onChange);\n    const errors = { foo: \"Required\" };\n    setStateRef(\"errors\", errors);\n    setStateRef(\"errors\", errors);\n    expect(onChange).toHaveBeenCalledTimes(1);\n    expect(onChange).toHaveBeenCalledWith({\n      ...initialState,\n      errors,\n      isValid: false,\n    });\n  });\n});\n"
  },
  {
    "path": "src/hooks/useState.ts",
    "content": "import { useReducer, useRef, useCallback } from \"react\";\nimport { dequal } from \"dequal/lite\";\n\nimport {\n  FormState,\n  FormStateReturn,\n  Observer,\n  OnStateChange,\n  SetStateRef,\n} from \"../types\";\nimport useLatest from \"./useLatest\";\nimport { get, getIsDirty, isEmptyObject, set } from \"../utils\";\n\nexport default <V>(\n  initialState: FormState<V>,\n  onChange?: OnStateChange<V>\n): FormStateReturn<V> => {\n  const [, forceUpdate] = useReducer((c) => c + 1, 0);\n  const stateRef = useRef(initialState);\n  const observersRef = useRef<Observer<V>[]>([\n    { usedState: {}, notify: forceUpdate },\n  ]);\n  const onChangeRef = useLatest(onChange || (() => undefined));\n\n  const setStateRef = useCallback<SetStateRef>(\n    (path, value, { fieldPath, shouldSkipUpdate, shouldForceUpdate } = {}) => {\n      const key = path.split(\".\")[0];\n\n      if (!key) {\n        if (!dequal(stateRef.current, value)) {\n          stateRef.current = value;\n          onChangeRef.current(stateRef.current);\n\n          observersRef.current.forEach(\n            ({ usedState, notify }) =>\n              !isEmptyObject(usedState) && notify(stateRef.current)\n          );\n        }\n\n        return;\n      }\n\n      if (\n        (path !== \"values\" && key === \"values\") ||\n        !dequal(get(stateRef.current, path), value)\n      ) {\n        const state = set(stateRef.current, path, value, true);\n        const {\n          errors,\n          dirty,\n          isDirty: prevIsDirty,\n          isValid: prevIsValid,\n          submitCount: prevSubmitCount,\n        } = state;\n        let { submitCount: currSubmitCount } = state;\n        const isDirty = key === \"dirty\" ? getIsDirty(dirty) : prevIsDirty;\n        const isValid = key === \"errors\" ? isEmptyObject(errors) : prevIsValid;\n        const submitCount =\n          key === \"isSubmitting\" && value\n            ? (currSubmitCount += 1)\n            : currSubmitCount;\n\n        stateRef.current = { ...state, isDirty, isValid, submitCount };\n        onChangeRef.current(stateRef.current);\n\n        if (shouldSkipUpdate) return;\n\n        path = fieldPath || path;\n        observersRef.current.forEach(\n          ({ usedState, notify }) =>\n            (shouldForceUpdate ||\n              Object.keys(usedState).some(\n                (k) => path.startsWith(k) || k.startsWith(path)\n              ) ||\n              (usedState.isDirty && isDirty !== prevIsDirty) ||\n              (usedState.isValid && isValid !== prevIsValid) ||\n              (usedState.submitCount && submitCount !== prevSubmitCount)) &&\n            notify(stateRef.current)\n        );\n      }\n    },\n    [onChangeRef]\n  );\n\n  return { stateRef, setStateRef, observersRef };\n};\n"
  },
  {
    "path": "src/index.ts",
    "content": "export { default as useForm } from \"./useForm\";\nexport { default as useFormMethods } from \"./useFormMethods\";\nexport { default as useFormState } from \"./useFormState\";\nexport { default as useControlled } from \"./useControlled\";\nexport { default as useFieldArray } from \"./useFieldArray\";\nexport { get, set, unset } from \"./utils\";\n"
  },
  {
    "path": "src/shared.test.ts",
    "content": "import { get, set, remove } from \"./shared\";\n\ndescribe(\"shared\", () => {\n  it.each([\"form-1\", undefined])(\"should work correctly\", (id) => {\n    expect(get(id)).toBeUndefined();\n    const methods = { method: \"🍎\" };\n    // @ts-expect-error\n    set(id, methods);\n    expect(get(id)).toEqual(methods);\n    remove(id);\n    expect(get(id)).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "src/shared.ts",
    "content": "import { Methods, ObjMap } from \"./types\";\n\nlet one: Methods | undefined;\nconst all: ObjMap<Methods> = {};\n\nexport const get = (id?: string): Methods => (id ? all[id] : (one as Methods));\n\nexport const set = (id: string | undefined, methods: Methods): void => {\n  if (id) {\n    all[id] = methods;\n  } else {\n    one = methods;\n  }\n};\n\nexport const remove = (id?: string): void => {\n  if (id) {\n    delete all[id];\n  } else {\n    one = undefined;\n  }\n};\n"
  },
  {
    "path": "src/types/global.d.ts",
    "content": "declare const __DEV__: boolean;\n\ninterface Window {\n  requestIdleCallback: (\n    callback: (deadline: {\n      readonly didTimeout: boolean;\n      timeRemaining: () => number;\n    }) => void,\n    options?: { timeout: number }\n  ) => any;\n}\n"
  },
  {
    "path": "src/types/index.ts",
    "content": "import {\n  FocusEventHandler,\n  MutableRefObject,\n  RefCallback,\n  SyntheticEvent,\n} from \"react\";\n\n// Utils\nexport type ObjMap<T = boolean> = Record<string, T>;\n\ntype DeepProps<V, T = any> = {\n  [K in keyof V]?: V[K] extends T ? T : DeepProps<V[K]>;\n};\n\n// Global\nexport type Methods<V = any> = {\n  validateOnChange: boolean;\n  shouldRemoveField: ShouldRemoveField;\n  initialStateRef: MutableRefObject<FormState<V>>;\n  fieldArrayRef: MutableRefObject<FieldArray>;\n  controlsRef: MutableRefObject<ObjMap>;\n  observersRef: MutableRefObject<Observer<V>[]>;\n  fieldValidatorsRef: MutableRefObject<ObjMap<FieldValidator<V>>>;\n  changedFieldRef: MutableRefObject<string | undefined>;\n  setStateRef: SetStateRef;\n  getNodeValue: GetNodeValue;\n  getFormState: GetFormState<V>;\n  setDefaultValue: SetDefaultValue;\n  setNodesOrValues: SetNodesOrValues<V>;\n  setTouchedMaybeValidate: SetTouchedMaybeValidate;\n  handleChangeEvent: HandleChangeEvent;\n} & FormMethods<V>;\n\n// useState\nexport type FormErrors<V> = DeepProps<V>;\n\nexport interface FormState<V = any> {\n  values: V;\n  touched: DeepProps<V, boolean>;\n  errors: FormErrors<V>;\n  isDirty: boolean;\n  dirty: DeepProps<V, boolean>;\n  isValidating: boolean;\n  isValid: boolean;\n  isSubmitting: boolean;\n  isSubmitted: boolean;\n  submitCount: number;\n}\n\nexport interface SetStateRef {\n  (\n    path: string,\n    value?: any,\n    options?: {\n      fieldPath?: string;\n      shouldSkipUpdate?: boolean;\n      shouldForceUpdate?: boolean;\n    }\n  ): void;\n}\n\nexport interface Observer<V> {\n  usedState: ObjMap;\n  notify: (state: FormState<V>) => void;\n}\n\nexport interface FormStateReturn<V> {\n  stateRef: MutableRefObject<FormState<V>>;\n  setStateRef: SetStateRef;\n  observersRef: MutableRefObject<Observer<V>[]>;\n}\n\n// useForm\nexport type FormValues = ObjMap<any>;\n\nexport type Handlers = {\n  [k in \"change\" | \"blur\" | \"submit\" | \"reset\"]?: (event: Event) => void;\n};\n\nexport type FieldElement =\n  | HTMLInputElement\n  | HTMLTextAreaElement\n  | HTMLSelectElement;\n\nexport type Fields = Map<\n  string,\n  {\n    field: FieldElement;\n    options?: (HTMLInputElement | HTMLOptionElement)[];\n  }\n>;\n\nexport type Parsers = ObjMap<Omit<FieldOptions, \"validate\">>;\n\nexport type FieldArray = ObjMap<{ fields: ObjMap; reset: () => void }>;\n\ninterface EventOptions<V> {\n  removeField: RemoveField;\n  getState: GetState;\n  setValue: SetValue;\n  setError: SetError;\n  setTouched: SetTouched;\n  setDirty: SetDirty;\n  clearErrors: ClearErrors;\n  runValidation: RunValidation;\n  focus: Focus;\n  reset: Reset<V>;\n  submit: Submit<V>;\n}\n\nexport type FieldNamesLike =\n  | boolean\n  | string[]\n  | ((names: string[]) => string[]);\n\ninterface ResetHandler<V> {\n  (values: V, options: EventOptions<V>, event?: Event | SyntheticEvent): void;\n}\n\nexport interface SubmitHandler<V = any> {\n  (\n    values: V,\n    options: EventOptions<V>,\n    event?: Event | SyntheticEvent\n  ): void | Promise<void>;\n}\n\nexport interface ErrorHandler<V = any> {\n  (\n    errors: FormErrors<V>,\n    options: EventOptions<V>,\n    event?: Event | SyntheticEvent\n  ): void;\n}\n\nexport interface OnStateChange<V> {\n  (formState: FormState<V>): void;\n}\n\ninterface FormValidator<V> {\n  (values: V):\n    | FormErrors<V>\n    | false\n    | void\n    | Promise<FormErrors<V> | false | void>;\n}\n\nexport type RegisterForm = RefCallback<HTMLElement>;\n\nexport interface FieldValidator<V> {\n  (value: any, values: V): any | Promise<any>;\n}\n\ninterface FieldParser {\n  (value: any): any;\n}\n\ninterface FieldOptions<V = any> {\n  validate?: FieldValidator<V>;\n  valueAsNumber?: boolean;\n  valueAsDate?: boolean;\n  parse?: FieldParser;\n}\n\nexport interface RegisterField<V = any> {\n  (value: FieldValidator<V> | FieldOptions<V>): (\n    field: FieldElement | null\n  ) => void;\n}\n\nexport interface HandleChangeEvent {\n  (name: string, value: any): void;\n}\n\nexport interface SetDefaultValue {\n  (name: string, value: any, shouldUpdateDefaultValue?: boolean): void;\n}\n\nexport interface SetNodesOrValues<V> {\n  (values: V, options?: { shouldSetValues?: boolean; fields?: string[] }): void;\n}\n\nexport interface SetTouchedMaybeValidate {\n  (name: string): void;\n}\n\nexport interface ShouldRemoveField {\n  (name: string): boolean;\n}\n\nexport interface GetNodeValue {\n  (name: string, fields?: Fields): any;\n}\n\nexport type Path = string | string[] | ObjMap<string>;\n\nexport interface GetFormState<V> {\n  (\n    path?: Path,\n    options?: {\n      errorWithTouched?: boolean;\n      defaultValues?: V;\n      methodName?: string;\n      callback?: (usedState: ObjMap) => void;\n    }\n  ): any;\n}\n\nexport interface Focus {\n  (name: string, delay?: number): void;\n}\n\nexport interface RemoveField {\n  (\n    name: string,\n    exclude?: (\"defaultValue\" | \"value\" | \"touched\" | \"dirty\" | \"error\")[]\n  ): void;\n}\n\nexport interface Use<V> {\n  (\n    path: Path,\n    options?: { defaultValues?: V; errorWithTouched?: boolean }\n  ): any;\n}\n\nexport interface GetState {\n  (path?: string | string[] | ObjMap<string>): any;\n}\n\nexport interface SetValue {\n  (\n    name: string,\n    value?: any | ((previousValue: any) => any),\n    options?: {\n      [k in \"shouldValidate\" | \"shouldTouched\" | \"shouldDirty\"]?: boolean;\n    }\n  ): void;\n}\n\nexport interface SetTouched {\n  (\n    name: string,\n    isTouched?: boolean,\n    options?: { shouldValidate?: boolean }\n  ): void;\n}\n\nexport interface SetDirty {\n  (name: string, isDirty?: boolean): void;\n}\n\nexport interface SetError {\n  (name: string, error?: any | ((previousError?: any) => any)): void;\n}\n\nexport interface ClearErrors {\n  (name?: string | string[]): void;\n}\n\nexport interface RunValidation {\n  (\n    name?: string | string[],\n    options?: { shouldFocus?: boolean }\n  ): Promise<boolean>;\n}\n\nexport interface Reset<V = any> {\n  (\n    values?: V | ((previousValues: V) => V) | null,\n    exclude?: (keyof FormState<V>)[] | null,\n    event?: SyntheticEvent\n  ): void;\n}\n\nexport interface Submit<V> {\n  (event?: SyntheticEvent): Promise<{\n    values?: V;\n    errors?: FormErrors<V>;\n  }>;\n}\n\nexport type FormConfig<V = any> = Partial<{\n  id: string;\n  defaultValues: V;\n  validate: FormValidator<V>;\n  validateOnChange: boolean;\n  validateOnBlur: boolean;\n  focusOnError: FieldNamesLike;\n  removeOnUnmounted: FieldNamesLike;\n  builtInValidationMode: \"message\" | \"state\" | false;\n  excludeFields: string[];\n  onReset: ResetHandler<V>;\n  onSubmit: SubmitHandler<V>;\n  onError: ErrorHandler<V>;\n  onStateChange: OnStateChange<V>;\n}>;\n\nexport interface FormMethods<V = any> {\n  form: RegisterForm;\n  field: RegisterField<V>;\n  focus: Focus;\n  removeField: RemoveField;\n  use: Use<V>;\n  getState: GetState;\n  setValue: SetValue;\n  setTouched: SetTouched;\n  setDirty: SetDirty;\n  setError: SetError;\n  clearErrors: ClearErrors;\n  runValidation: RunValidation;\n  reset: Reset<V>;\n  submit: Submit<V>;\n}\n\n// useFormState\nexport type FormStateConfig<V = any> = Partial<{\n  formId: string;\n  defaultValues: V;\n  errorWithTouched: boolean;\n}>;\n\nexport interface FormStateCallback {\n  (props: any): void;\n}\n\n// useControlled\ninterface ControlledParser {\n  (...args: any[]): any;\n}\n\ninterface ControlledFormatter {\n  (value: any): any;\n}\n\nexport type ControlledConfig<V = any> = Partial<{\n  formId: string;\n  defaultValue: any;\n  validate: FieldValidator<V>;\n  parse: ControlledParser;\n  format: ControlledFormatter;\n  errorWithTouched: boolean;\n  [k: string]: any;\n}>;\n\nexport interface FieldProps {\n  name: string;\n  value: any;\n  onChange: (...event: any[]) => void;\n  onBlur: FocusEventHandler;\n  [k: string]: any;\n}\n\nexport interface Meta {\n  error: any;\n  isTouched: boolean;\n  isDirty: boolean;\n}\n\nexport type ControlledReturn = [FieldProps, Meta];\n\n// useFieldArray\nexport type Keys = \"values\" | \"touched\" | \"errors\" | \"dirty\";\n\nexport interface StateHandler {\n  (fields: any[], type: Keys, lastIndex: number): any[];\n}\n\ntype HelperOptions = Partial<{\n  shouldTouched: boolean;\n  shouldDirty: boolean;\n}>;\n\nexport interface Push<T = any> {\n  (value: T, options?: HelperOptions): void;\n}\n\nexport interface Insert<T = any> {\n  (index: number, value: T, options?: HelperOptions): void;\n}\n\nexport interface Remove<T = any> {\n  (index: number): T | void;\n}\n\nexport interface Swap {\n  (indexA: number, indexB: number): void;\n}\n\nexport interface Move {\n  (from: number, to: number): void;\n}\n\nexport type FieldArrayConfig<T = any, V = any> = Partial<{\n  formId: string;\n  defaultValue: T[];\n  validate: FieldValidator<V>;\n}>;\n\nexport type FieldArrayReturn<T> = [\n  string[],\n  {\n    push: Push<T>;\n    insert: Insert<T>;\n    remove: Remove<T>;\n    swap: Swap;\n    move: Move;\n  }\n];\n"
  },
  {
    "path": "src/types/react-cool-form.d.ts",
    "content": "declare module \"react-cool-form\" {\n  import { FocusEventHandler, RefCallback, SyntheticEvent } from \"react\";\n\n  // Type utils\n  type ObjMap<T = boolean> = Record<string, T>;\n\n  type DeepProps<V, T = any> = {\n    [K in keyof V]?: V[K] extends T ? T : DeepProps<V[K]>;\n  };\n\n  // useForm\n  export type FormValues = ObjMap<any>;\n\n  export interface EventOptions<V extends FormValues = FormValues> {\n    removeField: RemoveField;\n    getState: GetState;\n    setValue: SetValue;\n    setTouched: SetTouched;\n    setDirty: SetDirty;\n    setError: SetError;\n    clearErrors: ClearErrors;\n    runValidation: RunValidation;\n    focus: Focus;\n    reset: Reset<V>;\n    submit: Submit<V>;\n  }\n\n  export type FormErrors<E extends FormValues = FormValues> = DeepProps<E>;\n\n  export type FormState<V extends FormValues = FormValues> = Readonly<{\n    values: V;\n    touched: DeepProps<V, boolean>;\n    errors: FormErrors<V>;\n    isDirty: boolean;\n    dirty: DeepProps<V, boolean>;\n    isValidating: boolean;\n    isValid: boolean;\n    isSubmitting: boolean;\n    isSubmitted: boolean;\n    submitCount: number;\n  }>;\n\n  export interface PreviousValuesFn<V extends FormValues = FormValues> {\n    (previousValues: V): V;\n  }\n\n  export interface PreviousValueFn {\n    (previousValue: any): any;\n  }\n\n  export interface PreviousErrorFn {\n    (previousError?: any): any;\n  }\n\n  export interface FormValidator<V extends FormValues = FormValues> {\n    (values: V):\n      | FormErrors<V>\n      | false\n      | void\n      | Promise<FormErrors<V> | false | void>;\n  }\n\n  export interface FieldValidator<V extends FormValues = FormValues> {\n    (value: any, values: V): any | Promise<any>;\n  }\n\n  export interface FieldParser<V = any, R = any> {\n    (value: V): R;\n  }\n\n  export interface FieldNamesFn<N extends string[] = string[]> {\n    (names: N): N;\n  }\n\n  export interface ResetHandler<V extends FormValues = FormValues> {\n    (values: V, options: EventOptions<V>, event?: Event | SyntheticEvent): void;\n  }\n\n  export interface SubmitHandler<V extends FormValues = FormValues> {\n    (\n      values: V,\n      options: EventOptions<V>,\n      event?: Event | SyntheticEvent\n    ): void | Promise<void>;\n  }\n\n  export interface ErrorHandler<V extends FormValues = FormValues> {\n    (\n      errors: FormErrors<V>,\n      options: EventOptions<V>,\n      event?: Event | SyntheticEvent\n    ): void;\n  }\n\n  export interface OnStateChange<V extends FormValues = FormValues> {\n    (formState: FormState<V>): void;\n  }\n\n  export type RegisterForm = RefCallback<HTMLElement>;\n\n  export interface RegisterFieldReturn {\n    (\n      field: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null\n    ): void;\n  }\n\n  export interface FieldOptions<V extends FormValues = FormValues> {\n    validate?: FieldValidator<V>;\n    valueAsNumber?: boolean;\n    valueAsDate?: boolean;\n    parse?: FieldParser;\n  }\n\n  export interface RegisterField<V extends FormValues = FormValues> {\n    (validate: FieldValidator<V>): RegisterFieldReturn;\n    (options: FieldOptions<V>): RegisterFieldReturn;\n  }\n\n  export interface Focus {\n    (name: string, delay?: number): void;\n  }\n\n  export interface RemoveField {\n    (\n      name: string,\n      exclude?: (\"defaultValue\" | \"value\" | \"touched\" | \"dirty\" | \"error\")[]\n    ): void;\n  }\n\n  export interface UseOptions<V extends FormValues = FormValues> {\n    defaultValues?: V;\n    errorWithTouched?: boolean;\n  }\n\n  export interface Use<V extends FormValues = FormValues> {\n    (path: string | string[] | ObjMap<string>, options?: UseOptions<V>): any;\n  }\n\n  export interface GetState {\n    (path?: string | string[] | ObjMap<string>): any;\n  }\n\n  export type SetValueOptions = {\n    [k in \"shouldValidate\" | \"shouldTouched\" | \"shouldDirty\"]?: boolean;\n  };\n\n  export interface SetValue {\n    (\n      name: string,\n      value: any | PreviousValueFn,\n      options?: SetValueOptions\n    ): void;\n  }\n\n  export type SetTouchedOptions = {\n    shouldValidate?: boolean;\n  };\n\n  export interface SetTouched {\n    (name: string, isTouched?: boolean, options?: SetTouchedOptions): void;\n  }\n\n  export interface SetDirty {\n    (name: string, isDirty?: boolean): void;\n  }\n\n  export interface SetError {\n    (name: string, error: any | PreviousErrorFn): void;\n  }\n\n  export interface ClearErrors {\n    (name?: string | string[]): void;\n  }\n\n  export type RunValidationOptions = {\n    shouldFocus?: boolean;\n  };\n\n  export interface RunValidation {\n    (\n      name?: string | string[],\n      options?: RunValidationOptions\n    ): Promise<boolean>;\n  }\n\n  export interface Reset<V extends FormValues = FormValues> {\n    (\n      values?: V | PreviousValuesFn<V> | null,\n      exclude?: (keyof FormState<V>)[] | null,\n      event?: SyntheticEvent\n    ): void;\n  }\n\n  export interface Submit<V extends FormValues = FormValues> {\n    (event?: SyntheticEvent): Promise<{\n      values?: V;\n      errors?: FormErrors<V>;\n    }>;\n  }\n\n  export type FormConfig<V extends FormValues = FormValues> = Partial<{\n    id: string;\n    defaultValues: V;\n    validate: FormValidator<V>;\n    validateOnChange: boolean;\n    validateOnBlur: boolean;\n    focusOnError: boolean | string[] | FieldNamesFn;\n    removeOnUnmounted: boolean | string[] | FieldNamesFn;\n    builtInValidationMode: \"message\" | \"state\" | false;\n    excludeFields: string[];\n    onReset: ResetHandler<V>;\n    onSubmit: SubmitHandler<V>;\n    onError: ErrorHandler<V>;\n    onStateChange: OnStateChange<V>;\n  }>;\n\n  export interface FormMethods<V extends FormValues = FormValues> {\n    form: RegisterForm;\n    field: RegisterField<V>;\n    focus: Focus;\n    removeField: RemoveField;\n    use: Use<V>;\n    getState: GetState;\n    setValue: SetValue;\n    setTouched: SetTouched;\n    setDirty: SetDirty;\n    setError: SetError;\n    clearErrors: ClearErrors;\n    runValidation: RunValidation;\n    reset: Reset<V>;\n    submit: Submit<V>;\n  }\n\n  export function useForm<V extends FormValues = FormValues>(\n    config?: FormConfig<V>\n  ): FormMethods<V>;\n\n  // useFormMethods\n  export function useFormMethods<V extends FormValues = FormValues>(\n    formId?: string\n  ): FormMethods<V>;\n\n  // useFormState\n  export type Path = string | string[] | ObjMap<string>;\n\n  export type FormStateConfig<V> = Partial<{\n    formId: string;\n    defaultValues: V;\n    errorWithTouched: boolean;\n  }>;\n\n  export interface FormStateCallback {\n    (props: any): void;\n  }\n\n  export function useFormState<V extends FormValues = FormValues>(\n    path: Path,\n    config?: FormStateConfig<V>,\n    formId?: string\n  ): any;\n\n  export function useFormState(\n    path: Path,\n    callback?: FormStateCallback,\n    formId?: string\n  ): any;\n\n  // useControlled\n  export interface ControlledParser<E extends any[] = any[], R = any> {\n    (...event: E): R;\n  }\n\n  export interface ControlledFormatter<V = any, R = any> {\n    (value: V): R;\n  }\n\n  export type ControlledConfig<V extends FormValues = FormValues> = Partial<{\n    formId: string;\n    defaultValue: any;\n    validate: FieldValidator<V>;\n    parse: ControlledParser;\n    format: ControlledFormatter;\n    errorWithTouched: boolean;\n    [k: string]: any;\n  }>;\n\n  export type ControlledReturn = [\n    {\n      name: string;\n      value: any;\n      onChange: (...event: any[]) => void;\n      onBlur: FocusEventHandler;\n      [k: string]: any;\n    },\n    { error: any; isTouched: boolean; isDirty: boolean }\n  ];\n\n  export function useControlled<V extends FormValues = FormValues>(\n    name: string,\n    config?: ControlledConfig<V>\n  ): ControlledReturn;\n\n  // useFieldArray\n  export type HelperOptions = Partial<{\n    shouldTouched: boolean;\n    shouldDirty: boolean;\n  }>;\n\n  export interface Push<T = any> {\n    (value: T, options?: HelperOptions): void;\n  }\n\n  export interface Insert<T = any> {\n    (index: number, value: T, options?: HelperOptions): void;\n  }\n\n  export interface Remove<T = any> {\n    (index: number): T | void;\n  }\n\n  export interface Swap {\n    (indexA: number, indexB: number): void;\n  }\n\n  export interface Move {\n    (from: number, to: number): void;\n  }\n\n  export type FieldArrayConfig<\n    T = any,\n    V extends FormValues = FormValues\n  > = Partial<{\n    formId: string;\n    defaultValue: T[];\n    validate: FieldValidator<V>;\n  }>;\n\n  export type FieldArrayReturn<T = any> = [\n    string[],\n    {\n      push: Push<T>;\n      insert: Insert<T>;\n      remove: Remove<T>;\n      swap: Swap;\n      move: Move;\n    }\n  ];\n\n  export function useFieldArray<T = any, V extends FormValues = FormValues>(\n    name: string,\n    config?: FieldArrayConfig<T, V>\n  ): FieldArrayReturn<T>;\n\n  // Utility functions\n  export function get(object: any, path: string, defaultValue?: unknown): any;\n\n  export function set(\n    object: any,\n    path: string,\n    value: unknown,\n    immutable?: boolean\n  ): any;\n\n  export function unset(object: any, path: string, immutable?: boolean): any;\n}\n"
  },
  {
    "path": "src/useControlled.test.tsx",
    "content": "/* eslint-disable react/no-unused-prop-types */\n\nimport { Dispatch, forwardRef, useState } from \"react\";\nimport {\n  render,\n  fireEvent,\n  waitFor,\n  screen,\n  act,\n} from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\n\nimport { FormConfig, FormMethods } from \"./types\";\nimport { isFunction } from \"./utils\";\nimport useForm from \"./useForm\";\nimport useFieldArray from \"./useFieldArray\";\nimport useControlled from \"./useControlled\";\n\ntype API = Omit<FormMethods, \"form\"> & {\n  show: boolean;\n  setShow: Dispatch<boolean>;\n};\n\ninterface Props extends FormConfig {\n  children: JSX.Element | ((api: API) => JSX.Element);\n  isShow?: boolean;\n  isFieldArray?: boolean;\n  onSubmit?: (values: any) => void;\n  onError?: (errors: any) => void;\n  onReset?: (values: any) => void;\n}\n\nconst Form = ({\n  children,\n  id,\n  isShow,\n  isFieldArray,\n  onSubmit = () => null,\n  onError = () => null,\n  onReset = () => null,\n  ...config\n}: Props) => {\n  const [show, setShow] = useState(!!isShow);\n  const { form, ...methods } = useForm({\n    id,\n    ...config,\n    onSubmit: (values) => onSubmit(values),\n    onError: (errors) => onError(errors),\n    onReset: (values) => onReset(values),\n  });\n  useFieldArray(isFieldArray ? \"foo\" : \"x\", { formId: id });\n\n  return (\n    <>\n      <form data-testid=\"form\" ref={form}>\n        {isFunction(children)\n          ? children({ ...methods, show, setShow })\n          : children}\n      </form>\n    </>\n  );\n};\n\nconst renderHelper = ({ children, ...rest }: Props) => {\n  let api: API;\n\n  render(\n    <Form {...rest}>\n      {(a) => {\n        api = a;\n        return isFunction(children) ? children(a) : children;\n      }}\n    </Form>\n  );\n\n  // @ts-expect-error\n  return api;\n};\n\nconst Field = forwardRef(\n  ({ name = \"foo\", onProps, onMeta, ...rest }: any, ref: any) => {\n    const [props, meta] = useControlled(name, { \"data-testid\": name, ...rest });\n    if (onProps) onProps(props);\n    if (onMeta) onMeta(meta);\n    return <input {...props} ref={ref} />;\n  }\n);\n\nconst CustomField = () => {\n  const [{ onChange, value }] = useControlled(\"foo\");\n  return (\n    <button\n      data-testid=\"foo\"\n      type=\"button\"\n      onClick={(e: any) => onChange(e.target.value)}\n    >\n      {value}\n    </button>\n  );\n};\n\ndescribe(\"useControlled\", () => {\n  console.warn = jest.fn();\n  const onSubmit = jest.fn();\n  const onError = jest.fn();\n  const onReset = jest.fn();\n\n  beforeEach(() => jest.clearAllMocks());\n\n  it(\"should throw form ID error\", () => {\n    expect(() => useControlled(\"foo\", { formId: \"form-1\" })).toThrow(\n      '💡 react-cool-form > useControlled: It must work with an \"useForm\" hook. See: https://react-cool-form.netlify.app/docs/api-reference/use-form'\n    );\n  });\n\n  it(\"should warn missing default value\", () => {\n    renderHelper({ children: <Field /> });\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"🍎\" } });\n    expect(console.warn).toHaveBeenCalledTimes(1);\n    expect(console.warn).toHaveBeenCalledWith(\n      '💡 react-cool-form > useControlled: Please provide a default value for \"foo\" field.'\n    );\n  });\n\n  it(\"should not warn missing default value for field-array\", () => {\n    renderHelper({ isFieldArray: true, children: <Field /> });\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"🍎\" } });\n    expect(console.warn).not.toHaveBeenCalled();\n  });\n\n  it.each([\"form\", \"controlled\"])(\n    \"should not warn missing default value\",\n    (type) => {\n      renderHelper({\n        defaultValues: type === \"form\" ? { foo: \"🍎\" } : undefined,\n        children: (\n          <Field defaultValue={type === \"controlled\" ? \"🍎\" : undefined} />\n        ),\n      });\n      expect(console.warn).not.toHaveBeenCalled();\n    }\n  );\n\n  it(\"should return values correctly\", () => {\n    const onProps = jest.fn();\n    const onMeta = jest.fn();\n    renderHelper({\n      children: <Field onProps={onProps} onMeta={onMeta} defaultValue=\"🍎\" />,\n    });\n    expect(onProps).toHaveBeenCalledWith({\n      \"data-testid\": expect.any(String),\n      name: expect.any(String),\n      value: expect.any(String),\n      onChange: expect.any(Function),\n      onBlur: expect.any(Function),\n    });\n    expect(onMeta).toHaveBeenCalledWith({\n      isTouched: expect.any(Boolean),\n      isDirty: expect.any(Boolean),\n    });\n  });\n\n  it(\"should call events correctly\", () => {\n    const onChange = jest.fn();\n    const onBlur = jest.fn();\n    renderHelper({ children: <Field onChange={onChange} onBlur={onBlur} /> });\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"🍎\" } });\n    expect(onChange).toHaveBeenCalled();\n    fireEvent.focusOut(screen.getByTestId(\"foo\"));\n    expect(onBlur).toHaveBeenCalled();\n  });\n\n  it.each([\"form\", \"controlled\", \"both-array\"])(\n    \"should set default value correctly from %s option\",\n    async (type) => {\n      const value = \"🍎\";\n      const format = jest.fn(() => value);\n      renderHelper({\n        isFieldArray: type === \"both-array\",\n        defaultValues:\n          type === \"form\" || type === \"both-array\" ? { foo: value } : undefined,\n        onSubmit,\n        children: (\n          <Field\n            format={format}\n            defaultValue={\n              type === \"controlled\" || type === \"both-array\" ? value : undefined\n            }\n          />\n        ),\n      });\n      expect(format).toHaveBeenCalledWith(value);\n      expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(value);\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: value })\n      );\n    }\n  );\n\n  it(\"should not set default value\", () => {\n    const { getState } = renderHelper({ children: <Field /> });\n    expect(getState(\"foo\")).toBeUndefined();\n  });\n\n  it.each([true, false])(\n    \"should use form-level default value first\",\n    async (isFieldArray) => {\n      const value = \"🍎\";\n      const format = jest.fn(() => value);\n      renderHelper({\n        isFieldArray,\n        defaultValues: { foo: value },\n        onSubmit,\n        children: <Field format={format} defaultValue=\"🍋\" />,\n      });\n      expect(format).toHaveBeenCalledWith(value);\n      expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(value);\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: value })\n      );\n    }\n  );\n\n  it(\"should not set default value for field-array\", () => {\n    const { getState } = renderHelper({\n      isFieldArray: true,\n      children: <Field />,\n    });\n    expect(getState(\"foo\")).toBeUndefined();\n  });\n\n  it.each([\"form\", \"controlled\", \"both-array\"])(\n    \"should reset value correctly from %s option\",\n    (type) => {\n      const defaultValues = { foo: \"🍎\" };\n      const { reset } = renderHelper({\n        isFieldArray: type === \"both-array\",\n        defaultValues:\n          type === \"form\" || type === \"both-array\" ? defaultValues : undefined,\n        onReset,\n        children: (\n          <Field\n            defaultValue={\n              type === \"controlled\" || type === \"both-array\"\n                ? defaultValues.foo\n                : undefined\n            }\n          />\n        ),\n      });\n      act(() => reset());\n      expect(onReset).toHaveBeenCalledWith(defaultValues);\n    }\n  );\n\n  it.each([false, true])(\n    'should update value correctly when using \"defaultValue\" option',\n    async (isFieldArray) => {\n      renderHelper({\n        isFieldArray,\n        onSubmit,\n        children: <Field defaultValue=\"🍎\" />,\n      });\n      const value = \"🍋\";\n      fireEvent.input(screen.getByTestId(\"foo\"), { target: { value } });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => {\n        expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(\n          value\n        );\n        expect(onSubmit).toHaveBeenCalledWith({ foo: value });\n      });\n    }\n  );\n\n  it(\"should run validation on submit\", async () => {\n    const onMeta = jest.fn();\n    const errors = { foo: \"Required\" };\n    const { getState } = renderHelper({\n      onSubmit,\n      onError,\n      children: (\n        <Field\n          onMeta={onMeta}\n          validate={async (val: string) => (!val.length ? errors.foo : false)}\n          defaultValue=\"\"\n        />\n      ),\n    });\n\n    fireEvent.submit(screen.getByTestId(\"form\"));\n    expect(getState(\"isValidating\")).toBeTruthy();\n    await waitFor(() => expect(onError).toHaveBeenCalledWith(errors));\n    expect(onMeta).toHaveBeenLastCalledWith({\n      error: errors.foo,\n      isTouched: expect.any(Boolean),\n      isDirty: expect.any(Boolean),\n    });\n    expect(getState(\"isValidating\")).toBeFalsy();\n    expect(getState(\"isValid\")).toBeFalsy();\n\n    const value = \"🍎\";\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value } });\n    fireEvent.submit(screen.getByTestId(\"form\"));\n    expect(getState(\"isValidating\")).toBeTruthy();\n    await waitFor(() => {\n      expect(onSubmit).toHaveBeenCalledWith({ foo: value });\n      expect(onError).toHaveBeenCalledTimes(1);\n    });\n    expect(onMeta).toHaveBeenLastCalledWith({\n      isTouched: expect.any(Boolean),\n      isDirty: expect.any(Boolean),\n    });\n    expect(getState(\"errors\")).toEqual({});\n    expect(getState(\"isValidating\")).toBeFalsy();\n    expect(getState(\"isValid\")).toBeTruthy();\n  });\n\n  it(\"should run validation on change\", async () => {\n    const error = \"Too short\";\n    const { getState } = renderHelper({\n      children: (\n        <Field\n          validate={(val: string) => (val.length < 5 ? error : false)}\n          defaultValue=\"\"\n        />\n      ),\n    });\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"123\" } });\n    await waitFor(() => expect(getState(\"errors\")).toEqual({ foo: error }));\n  });\n\n  it(\"should run validation on blur\", async () => {\n    const error = \"Required\";\n    const { getState } = renderHelper({\n      children: (\n        <Field\n          validate={(val: string) => (!val.length ? error : false)}\n          defaultValue=\"\"\n        />\n      ),\n    });\n    fireEvent.focusOut(screen.getByTestId(\"foo\"));\n    await waitFor(() => expect(getState(\"errors\")).toEqual({ foo: error }));\n  });\n\n  it(\"should avoid repeatedly validation\", async () => {\n    const validate = jest.fn();\n    renderHelper({\n      validate,\n      children: <input data-testid=\"foo\" name=\"foo\" />,\n    });\n    const foo = screen.getByTestId(\"foo\");\n\n    fireEvent.focusOut(foo);\n    await waitFor(() => expect(validate).toHaveBeenCalled());\n\n    validate.mockClear();\n    fireEvent.input(foo);\n    await waitFor(() => expect(validate).toHaveBeenCalled());\n    fireEvent.focusOut(foo);\n    await waitFor(() => expect(validate).toHaveBeenCalledTimes(1));\n  });\n\n  it('should ignore \"field\" method', async () => {\n    const mockDate = \"2050-01-09\";\n    renderHelper({\n      onSubmit,\n      onError,\n      children: ({ field }: API) => (\n        <Field\n          type=\"date\"\n          ref={field({ validate: () => \"Required\", valueAsNumber: true })}\n          defaultValue={mockDate}\n        />\n      ),\n    });\n    fireEvent.submit(screen.getByTestId(\"form\"));\n    await waitFor(() => {\n      expect(onSubmit).toHaveBeenCalledWith({ foo: mockDate });\n      expect(onError).not.toHaveBeenCalled();\n    });\n  });\n\n  it.each([undefined, \"form-1\"])(\"should work with form ID\", async (formId) => {\n    renderHelper({\n      id: formId,\n      onSubmit,\n      children: <Field formId={formId} />,\n    });\n    const value = \"🍎\";\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value } });\n    fireEvent.submit(screen.getByTestId(\"form\"));\n    await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ foo: value }));\n  });\n\n  it(\"should handle text correctly\", async () => {\n    renderHelper({\n      onSubmit,\n      children: <input data-testid=\"text\" name=\"text\" />,\n    });\n    const value = \"🍎\";\n    fireEvent.input(screen.getByTestId(\"text\"), { target: { value } });\n    fireEvent.submit(screen.getByTestId(\"form\"));\n    await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ text: value }));\n  });\n\n  it(\"should handle checkboxes correctly\", async () => {\n    renderHelper({\n      onSubmit,\n      children: (\n        <>\n          <Field\n            data-testid=\"checkboxes-0\"\n            name=\"checkboxes\"\n            type=\"checkbox\"\n            value=\"🍎\"\n          />\n          <Field name=\"checkboxes\" type=\"checkbox\" value=\"🍋\" />\n        </>\n      ),\n    });\n    const checkboxes0 = screen.getByTestId(\"checkboxes-0\") as HTMLInputElement;\n    userEvent.click(checkboxes0);\n    fireEvent.submit(screen.getByTestId(\"form\"));\n    await waitFor(() =>\n      expect(onSubmit).toHaveBeenCalledWith({ checkboxes: [checkboxes0.value] })\n    );\n  });\n\n  it(\"should handle multiple select correctly\", async () => {\n    renderHelper({\n      onSubmit,\n      children: (\n        <select data-testid=\"selects\" name=\"selects\" multiple>\n          <option data-testid=\"selects-0\" value=\"🍎\">\n            🍎\n          </option>\n          <option value=\"🍋\">🍋</option>\n        </select>\n      ),\n    });\n    const selects0 = screen.getByTestId(\"selects-0\") as HTMLInputElement;\n    userEvent.selectOptions(screen.getByTestId(\"selects\"), [selects0.value]);\n    fireEvent.submit(screen.getByTestId(\"form\"));\n    await waitFor(() =>\n      expect(onSubmit).toHaveBeenCalledWith({ selects: [selects0.value] })\n    );\n  });\n\n  it(\"should handle custom field correctly\", async () => {\n    renderHelper({\n      onSubmit,\n      children: <CustomField />,\n    });\n    const value = \"🍎\";\n    fireEvent.click(screen.getByTestId(\"foo\"), { target: { value } });\n    fireEvent.submit(screen.getByTestId(\"form\"));\n    await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ foo: value }));\n  });\n\n  it(\"should parse value correctly\", async () => {\n    renderHelper({\n      onSubmit,\n      children: <Field parse={({ target }: any) => `${target.value}🍋`} />,\n    });\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"🍎\" } });\n    fireEvent.submit(screen.getByTestId(\"form\"));\n    await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ foo: \"🍎🍋\" }));\n  });\n\n  it(\"should format value correctly\", () => {\n    renderHelper({\n      onSubmit,\n      children: (\n        <Field\n          format={(val: string) => val.replace(\"🍋\", \"\")}\n          defaultValue=\"🍎🍋\"\n        />\n      ),\n    });\n    expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(\"🍎\");\n  });\n\n  describe(\"conditional fields\", () => {\n    const initialState = {\n      values: {},\n      touched: {},\n      errors: {},\n      isDirty: false,\n      dirty: {},\n      isValidating: false,\n      isValid: true,\n      isSubmitting: false,\n      isSubmitted: false,\n      submitCount: 0,\n    };\n\n    it.each([\"form\", \"field\"])(\n      \"should set %s-level default value correctly\",\n      async (type) => {\n        const formValue = \"🍎\";\n        const fieldValue = \"🍋\";\n        const { getState, setError, setTouched, setDirty, setShow } =\n          renderHelper({\n            defaultValues: type === \"form\" ? { foo: formValue } : undefined,\n            children: ({ show }: API) => (\n              <>\n                {show && (\n                  <Field\n                    defaultValue={type === \"field\" ? fieldValue : undefined}\n                  />\n                )}\n              </>\n            ),\n          });\n\n        act(() => setShow(true));\n        await waitFor(() => {\n          expect(getState(\"foo\")).toBe(\n            type === \"form\" ? formValue : fieldValue\n          );\n          expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(\n            type === \"form\" ? formValue : fieldValue\n          );\n        });\n\n        act(() => {\n          setError(\"foo\", \"Required\");\n          setTouched(\"foo\", true, { shouldValidate: false });\n          setDirty(\"foo\");\n          setShow(false);\n        });\n        await waitFor(() => expect(getState()).toEqual(initialState));\n\n        act(() => setShow(true));\n        await waitFor(() => {\n          expect(getState()).toEqual({\n            ...initialState,\n            values: { foo: type === \"field\" ? fieldValue : undefined },\n          });\n          expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(\n            type === \"field\" ? fieldValue : \"\"\n          );\n        });\n      }\n    );\n\n    it.each([false, [], () => []])(\n      \"should not remove field\",\n      async (removeOnUnmounted) => {\n        const value = \"🍎\";\n        const { getState, setError, setTouched, setDirty, setShow } =\n          renderHelper({\n            isShow: true,\n            removeOnUnmounted,\n            children: ({ show }: API) => (\n              <>{show && <Field defaultValue={value} />}</>\n            ),\n          });\n\n        act(() => {\n          setError(\"foo\", \"Required\");\n          setTouched(\"foo\", true, { shouldValidate: false });\n          setDirty(\"foo\");\n          setShow(false);\n        });\n        await waitFor(() =>\n          expect(getState()).toEqual({\n            ...initialState,\n            values: { foo: value },\n            errors: { foo: \"Required\" },\n            isValid: false,\n            touched: { foo: true },\n            dirty: { foo: true },\n            isDirty: true,\n          })\n        );\n\n        act(() => setShow(true));\n        await waitFor(() =>\n          expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(\n            value\n          )\n        );\n      }\n    );\n\n    it(\"should initialize value correctly\", () => {\n      const value = \"🍎\";\n      const { getState, setShow, removeField } = renderHelper({\n        isShow: true,\n        removeOnUnmounted: false,\n        children: ({ show }: API) => (\n          <>{show && <Field defaultValue={value} />}</>\n        ),\n      });\n      act(() => {\n        setShow(false);\n        removeField(\"foo\", [\"defaultValue\"]);\n      });\n      expect(getState(\"foo\")).toBeUndefined();\n      act(() => setShow(true));\n      expect(getState(\"foo\")).toBe(value);\n    });\n  });\n});\n"
  },
  {
    "path": "src/useControlled.ts",
    "content": "import { useEffect } from \"react\";\n\nimport {\n  ControlledConfig,\n  ControlledReturn,\n  FormValues,\n  Methods,\n} from \"./types\";\nimport * as shared from \"./shared\";\nimport {\n  get,\n  invariant,\n  isFieldArray,\n  isFieldElement,\n  isUndefined,\n  warn,\n} from \"./utils\";\nimport useFormState from \"./useFormState\";\n\nexport default <V extends FormValues = FormValues>(\n  name: string,\n  {\n    formId,\n    defaultValue,\n    validate,\n    parse,\n    format,\n    errorWithTouched,\n    ...props\n  }: ControlledConfig<V> = {}\n): ControlledReturn => {\n  const methods: Methods<V> = shared.get(formId);\n\n  invariant(\n    !methods,\n    '💡 react-cool-form > useControlled: It must work with an \"useForm\" hook. See: https://react-cool-form.netlify.app/docs/api-reference/use-form'\n  );\n\n  const meta = useFormState(\n    {\n      value: `values.${name}`,\n      error: `errors.${name}`,\n      isTouched: `touched.${name}`,\n      isDirty: `dirty.${name}`,\n    },\n    { formId, errorWithTouched }\n  );\n  const {\n    shouldRemoveField,\n    initialStateRef,\n    fieldArrayRef,\n    controlsRef,\n    fieldValidatorsRef,\n    changedFieldRef,\n    getState,\n    getNodeValue,\n    setDefaultValue,\n    setTouchedMaybeValidate,\n    handleChangeEvent,\n    removeField,\n  } = methods;\n\n  useEffect(\n    () => {\n      const isFieldArr = isFieldArray(fieldArrayRef.current, name);\n      const initialVal = get(initialStateRef.current.values, name);\n\n      if (isUndefined(initialVal)) {\n        if (\n          !isUndefined(defaultValue) &&\n          (!isFieldArr ||\n            !isUndefined(\n              get(initialStateRef.current.values, name.split(\".\")[0])\n            ))\n        ) {\n          setDefaultValue(name, defaultValue);\n        } else if (!isFieldArr) {\n          warn(\n            `💡 react-cool-form > useControlled: Please provide a default value for \"${name}\" field.`\n          );\n        }\n      } else if (isUndefined(getState(name))) {\n        setDefaultValue(name, initialVal);\n      }\n\n      return () => {\n        if (shouldRemoveField(name))\n          removeField(\n            name,\n            !isFieldArr ||\n              isUndefined(\n                // eslint-disable-next-line react-hooks/exhaustive-deps\n                get(initialStateRef.current.values, name.split(\".\")[0])\n              )\n              ? undefined\n              : [\"defaultValue\"]\n          );\n      };\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    []\n  );\n\n  controlsRef.current[name] = true;\n  if (validate) fieldValidatorsRef.current[name] = validate;\n\n  const { onChange, onBlur, ...restProps } = props;\n  let value = get(initialStateRef.current.values, name);\n  value = !isUndefined(value) ? value : defaultValue;\n  value = !isUndefined(meta.value) ? meta.value : value;\n  value = (format ? format(value) : value) ?? \"\";\n\n  return [\n    {\n      name,\n      value,\n      onChange: (...event) => {\n        let val;\n\n        if (parse) {\n          val = parse(...event);\n        } else {\n          const e = event[0];\n          val =\n            e?.nativeEvent instanceof Event && isFieldElement(e.target)\n              ? getNodeValue(name)\n              : e;\n        }\n\n        handleChangeEvent(name, val);\n        if (onChange) onChange(...event);\n        changedFieldRef.current = name;\n      },\n      onBlur: (e) => {\n        setTouchedMaybeValidate(name);\n        if (onBlur) onBlur(e);\n        changedFieldRef.current = undefined;\n      },\n      ...restProps,\n    },\n    { error: meta.error, isTouched: !!meta.isTouched, isDirty: !!meta.isDirty },\n  ];\n};\n"
  },
  {
    "path": "src/useFieldArray.test.tsx",
    "content": "/* eslint-disable react/no-unused-prop-types */\n\nimport { Dispatch, useState } from \"react\";\nimport {\n  render,\n  fireEvent,\n  screen,\n  act,\n  waitFor,\n} from \"@testing-library/react\";\n\nimport {\n  FieldArrayConfig,\n  FieldNamesLike,\n  FormMethods,\n  Insert,\n  Move,\n  Push,\n  Remove,\n  Swap,\n} from \"./types\";\nimport useForm from \"./useForm\";\nimport useFieldArray from \"./useFieldArray\";\nimport useControlled from \"./useControlled\";\n\ntype API = Omit<FormMethods, \"form\"> & {\n  fields: string[];\n  insert: Insert;\n  move: Move;\n  push: Push;\n  remove: Remove;\n  swap: Swap;\n  show: boolean;\n  setShow: Dispatch<boolean>;\n};\n\ninterface Config extends FieldArrayConfig {\n  children: (api: API) => JSX.Element | JSX.Element[] | null;\n  isShow: boolean;\n  defaultValues: any;\n  validateOnChange: boolean;\n  removeOnUnmounted: FieldNamesLike;\n  formValidate: (values: any) => void;\n  onSubmit: (values: any) => void;\n  onRender: () => void;\n}\n\ntype Props = Partial<Config>;\n\nconst Form = ({\n  children,\n  isShow,\n  formId,\n  defaultValues,\n  validateOnChange,\n  removeOnUnmounted,\n  formValidate,\n  onSubmit = () => null,\n  onRender = () => null,\n  ...rest\n}: Props) => {\n  const [show, setShow] = useState(!!isShow);\n  const { form, ...methods } = useForm({\n    id: formId,\n    defaultValues,\n    removeOnUnmounted,\n    validateOnChange,\n    validate: formValidate,\n    onSubmit: (values) => onSubmit(values),\n  });\n  const [fields, helpers] = useFieldArray(\"foo\", { ...rest, formId });\n\n  onRender();\n\n  return (\n    <form data-testid=\"form\" ref={form}>\n      {children\n        ? children({\n            ...methods,\n            fields,\n            ...helpers,\n            show,\n            setShow,\n          })\n        : null}\n    </form>\n  );\n};\n\nconst renderHelper = ({ children, ...rest }: Props = {}) => {\n  let api: API;\n\n  const { container } = render(\n    <Form {...rest}>\n      {(a) => {\n        api = a;\n        return children ? children(a) : null;\n      }}\n    </Form>\n  );\n\n  // @ts-expect-error\n  return { ...api, container };\n};\n\nconst Field = ({ name, ...rest }: any) => {\n  const [props] = useControlled(name, rest);\n  return <input {...props} />;\n};\n\nconst FieldArray = (props: any) => {\n  const [fields] = useFieldArray(\"foo\", props);\n  return (\n    <>\n      {fields.map((name) => (\n        <div key={name}>\n          <input data-testid={`${name}.a`} name={`${name}.a`} />\n          <Field data-testid={`${name}.b`} name={`${name}.b`} />\n        </div>\n      ))}\n    </>\n  );\n};\n\ndescribe(\"useFieldArray\", () => {\n  const onSubmit = jest.fn();\n  const onRender = jest.fn();\n  const value = [{ a: \"🍎\", b: \"🍎\" }];\n\n  beforeEach(() => jest.clearAllMocks());\n\n  it(\"should throw form ID error\", () => {\n    expect(() => useFieldArray(\"values\", { formId: \"form-1\" })).toThrow(\n      '💡 react-cool-form > useFieldArray: It must work with an \"useForm\" hook. See: https://react-cool-form.netlify.app/docs/api-reference/use-form'\n    );\n  });\n\n  it.each([\"form\", \"array\"])(\n    \"should set default value correctly from %s option\",\n    async (type) => {\n      renderHelper({\n        defaultValues: type === \"form\" ? { foo: value } : undefined,\n        defaultValue: type === \"array\" ? value : undefined,\n        onSubmit,\n        children: ({ fields }: API) =>\n          fields.map((name) => (\n            <div key={name}>\n              <input data-testid={`${name}.a`} name={`${name}.a`} />\n              <Field data-testid={`${name}.b`} name={`${name}.b`} />\n            </div>\n          )),\n      });\n      expect(screen.getAllByRole(\"textbox\")).toHaveLength(2);\n      expect((screen.getByTestId(\"foo[0].a\") as HTMLInputElement).value).toBe(\n        value[0].a\n      );\n      expect((screen.getByTestId(\"foo[0].b\") as HTMLInputElement).value).toBe(\n        value[0].b\n      );\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: value })\n      );\n    }\n  );\n\n  it(\"should use form-level default value first\", async () => {\n    const defaultValues = { foo: value };\n    renderHelper({\n      defaultValues,\n      defaultValue: [{ a: \"🍋\" }],\n      onSubmit,\n    });\n    fireEvent.submit(screen.getByTestId(\"form\"));\n    await waitFor(() => expect(onSubmit).toHaveBeenCalledWith(defaultValues));\n  });\n\n  it.each([undefined, true, value])(\n    'should return \"fields\" correctly',\n    (val) => {\n      const { fields, getState } = renderHelper({\n        defaultValues: { foo: val },\n      });\n      expect(fields).toEqual(Array.isArray(val) ? [\"foo[0]\"] : []);\n      expect(getState(\"foo\")).toEqual(val);\n    }\n  );\n\n  it(\"should push value correctly\", async () => {\n    const { push, getState } = renderHelper({\n      defaultValues: { foo: value },\n      onRender,\n      children: ({ fields }: API) =>\n        fields.map((name) => (\n          <div key={name}>\n            <input data-testid={`${name}.a`} name={`${name}.a`} />\n            <Field data-testid={`${name}.b`} name={`${name}.b`} />\n          </div>\n        )),\n    });\n    const newValue1 = { a: \"🍋\", b: \"🍋\" };\n    const newValue2 = { a: \"🥝\", b: \"🥝\" };\n    act(() => {\n      push(newValue1, { shouldDirty: false });\n      push(newValue2, { shouldTouched: true });\n    });\n    expect(screen.getAllByRole(\"textbox\")).toHaveLength(6);\n    await waitFor(() => {\n      expect((screen.getByTestId(\"foo[1].a\") as HTMLInputElement).value).toBe(\n        newValue1.a\n      );\n      expect((screen.getByTestId(\"foo[1].b\") as HTMLInputElement).value).toBe(\n        newValue1.b\n      );\n      expect((screen.getByTestId(\"foo[2].a\") as HTMLInputElement).value).toBe(\n        newValue2.a\n      );\n      expect((screen.getByTestId(\"foo[2].b\") as HTMLInputElement).value).toBe(\n        newValue2.b\n      );\n    });\n    expect(getState(\"foo\")).toEqual([...value, newValue1, newValue2]);\n    expect(getState(\"dirty.foo\")).toEqual([, , { a: true, b: true }]);\n    expect(getState(\"touched.foo\")).toEqual([, , { a: true, b: true }]);\n    expect(onRender).toHaveBeenCalledTimes(2);\n  });\n\n  it(\"should insert value correctly\", async () => {\n    const { insert, getState } = renderHelper({\n      defaultValues: { foo: value },\n      onRender,\n      children: ({ fields }: API) =>\n        fields.map((name) => (\n          <div key={name}>\n            <input data-testid={`${name}.a`} name={`${name}.a`} />\n            <Field data-testid={`${name}.b`} name={`${name}.b`} />\n          </div>\n        )),\n    });\n\n    let val = [...value, { a: \"🍋\", b: \"🍋\" }];\n    act(() => insert(1, val[1], { shouldTouched: true }));\n    expect(screen.getAllByRole(\"textbox\")).toHaveLength(4);\n    await waitFor(() => {\n      expect((screen.getByTestId(\"foo[1].a\") as HTMLInputElement).value).toBe(\n        val[1].a\n      );\n      expect((screen.getByTestId(\"foo[1].b\") as HTMLInputElement).value).toBe(\n        val[1].b\n      );\n    });\n    expect(getState(\"foo\")).toEqual(val);\n    expect(getState(\"dirty.foo\")).toEqual([, { a: true, b: true }]);\n    expect(getState(\"touched.foo\")).toEqual([, { a: true, b: true }]);\n    expect(onRender).toHaveBeenCalledTimes(2);\n\n    val = [...val, { a: \"🥝\", b: \"🥝\" }];\n    act(() => insert(2, val[2], { shouldDirty: false }));\n    expect(screen.getAllByRole(\"textbox\")).toHaveLength(6);\n    await waitFor(() => {\n      expect((screen.getByTestId(\"foo[2].a\") as HTMLInputElement).value).toBe(\n        val[2].a\n      );\n      expect((screen.getByTestId(\"foo[2].b\") as HTMLInputElement).value).toBe(\n        val[2].b\n      );\n    });\n    expect(getState(\"foo\")).toEqual(val);\n    expect(getState(\"dirty.foo\")).toEqual([, { a: true, b: true }]);\n    expect(getState(\"touched.foo\")).toEqual([, { a: true, b: true }]);\n\n    val = [{ a: \"🍒\", b: \"🍒\" }, ...val];\n    act(() => insert(0, val[0], { shouldDirty: false }));\n    expect(screen.getAllByRole(\"textbox\")).toHaveLength(8);\n    await waitFor(() => {\n      expect((screen.getByTestId(\"foo[0].a\") as HTMLInputElement).value).toBe(\n        val[0].a\n      );\n      expect((screen.getByTestId(\"foo[0].b\") as HTMLInputElement).value).toBe(\n        val[0].b\n      );\n    });\n    expect(getState(\"foo\")).toEqual(val);\n    expect(getState(\"dirty.foo\")).toEqual([, , { a: true, b: true }]);\n    expect(getState(\"touched.foo\")).toEqual([, , { a: true, b: true }]);\n  });\n\n  it.each([\"swap\", \"move\"])(\"should %s values correctly\", (type) => {\n    const { push, swap, move, getState } = renderHelper({\n      defaultValues: { foo: value },\n      onRender,\n      children: ({ fields }: API) =>\n        fields.map((name) => (\n          <div key={name}>\n            <input name={`${name}.a`} />\n            <Field name={`${name}.b`} />\n          </div>\n        )),\n    });\n    const newValue = { a: \"🍋\", b: \"🍋\" };\n    act(() => {\n      push(newValue, { shouldTouched: true });\n      if (type === \"swap\") {\n        swap(0, 1);\n      } else {\n        move(1, 0);\n      }\n    });\n    expect(getState(\"foo\")).toEqual([newValue, ...value]);\n    expect(getState(\"touched.foo\")).toEqual([{ a: true, b: true }, undefined]);\n    expect(getState(\"dirty.foo\")).toEqual([{ a: true, b: true }, undefined]);\n    expect(onRender).toHaveBeenCalledTimes(2);\n  });\n\n  it(\"should remove value correctly\", () => {\n    const { push, remove, getState } = renderHelper({\n      onRender,\n      children: ({ fields }: API) =>\n        fields.map((name) => (\n          <div key={name}>\n            <input name={`${name}.a`} />\n            <Field name={`${name}.b`} />\n          </div>\n        )),\n    });\n    const val = [...value, { a: \"🍋\", b: \"🍋\" }];\n    act(() => {\n      push(val[0], { shouldTouched: true });\n      push(val[1], { shouldTouched: true });\n      expect(remove(1)).toEqual(val[1]);\n    });\n    expect(getState(\"foo\")).toEqual([val[0]]);\n    expect(getState(\"dirty.foo\")).toEqual([{ a: true, b: true }]);\n    expect(getState(\"touched.foo\")).toEqual([{ a: true, b: true }]);\n    act(() => expect(remove(0)).toEqual(val[0]));\n    expect(getState(\"foo\")).toEqual([]);\n    expect(getState(\"dirty.foo\")).toEqual([]);\n    expect(getState(\"touched.foo\")).toEqual([]);\n  });\n\n  it(\"should set value correctly\", () => {\n    const defaultValue = [...value, { a: \"🍋\", b: \"🍋\" }];\n    const { setValue, reset, getState, push, remove } = renderHelper({\n      defaultValues: { foo: defaultValue },\n      children: ({ fields }: API) =>\n        fields.map((name) => (\n          <div key={name}>\n            <input data-testid={`${name}.a`} name={`${name}.a`} />\n            <Field data-testid={`${name}.b`} name={`${name}.b`} />\n          </div>\n        )),\n    });\n    const fooA = screen.getByTestId(\"foo[0].a\") as HTMLInputElement;\n    const fooB = screen.getByTestId(\"foo[0].b\") as HTMLInputElement;\n    const target = { value: \"🥝\" };\n\n    fireEvent.input(fooA, { target });\n    fireEvent.input(fooB, { target });\n    act(() => setValue(\"foo\", defaultValue));\n    expect(fooA.value).toBe(defaultValue[0].a);\n    expect(fooB.value).toBe(defaultValue[0].b);\n    expect(getState(\"foo\")).toEqual(defaultValue);\n\n    act(() => push({ a: \"🍒\", b: \"🍒\" }));\n    fireEvent.input(fooA, { target });\n    fireEvent.input(fooB, { target });\n    act(() => setValue(\"foo\", defaultValue));\n    expect(screen.getAllByRole(\"textbox\")).toHaveLength(4);\n    expect(fooA.value).toBe(defaultValue[0].a);\n    expect(fooB.value).toBe(defaultValue[0].b);\n    expect(getState(\"foo\")).toEqual(defaultValue);\n\n    act(() => {\n      reset();\n      remove(1);\n    });\n    fireEvent.input(fooA, { target });\n    fireEvent.input(fooB, { target });\n    act(() => setValue(\"foo\", defaultValue));\n    expect(screen.getAllByRole(\"textbox\")).toHaveLength(4);\n    expect(fooA.value).toBe(defaultValue[0].a);\n    expect(fooB.value).toBe(defaultValue[0].b);\n    expect(getState(\"foo\")).toEqual(defaultValue);\n  });\n\n  it.each([\"form\", \"array\"])(\n    \"should reset value correctly from %s default option\",\n    (type) => {\n      const defaultValue = [...value, { a: \"🍋\", b: \"🍋\" }];\n      const { reset, getState, push, remove } = renderHelper({\n        defaultValues: type === \"form\" ? { foo: defaultValue } : undefined,\n        defaultValue: type === \"array\" ? defaultValue : undefined,\n        children: ({ fields }: API) =>\n          fields.map((name) => (\n            <div key={name}>\n              <input data-testid={`${name}.a`} name={`${name}.a`} />\n              <Field data-testid={`${name}.b`} name={`${name}.b`} />\n            </div>\n          )),\n      });\n      const fooA = screen.getByTestId(\"foo[0].a\") as HTMLInputElement;\n      const fooB = screen.getByTestId(\"foo[0].b\") as HTMLInputElement;\n      const target = { value: \"🥝\" };\n\n      fireEvent.input(fooA, { target });\n      fireEvent.input(fooB, { target });\n      act(() => reset());\n      expect(fooA.value).toBe(defaultValue[0].a);\n      expect(fooB.value).toBe(defaultValue[0].b);\n      expect(getState(\"foo\")).toEqual(defaultValue);\n      expect(getState(\"touched.foo\")).toBeUndefined();\n      expect(getState(\"dirty.foo\")).toBeUndefined();\n\n      act(() => push({ a: \"🍒\", b: \"🍒\" }));\n      fireEvent.input(fooA, { target });\n      fireEvent.input(fooB, { target });\n      act(() => reset());\n      expect(screen.getAllByRole(\"textbox\")).toHaveLength(4);\n      expect(fooA.value).toBe(defaultValue[0].a);\n      expect(fooB.value).toBe(defaultValue[0].b);\n      expect(getState(\"foo\")).toEqual(defaultValue);\n      expect(getState(\"touched.foo\")).toBeUndefined();\n      expect(getState(\"dirty.foo\")).toBeUndefined();\n\n      act(() => {\n        remove(1);\n      });\n      fireEvent.input(fooA, { target });\n      fireEvent.input(fooB, { target });\n      act(() => reset());\n      expect(screen.getAllByRole(\"textbox\")).toHaveLength(4);\n      expect(fooA.value).toBe(defaultValue[0].a);\n      expect(fooB.value).toBe(defaultValue[0].b);\n      expect(getState(\"foo\")).toEqual(defaultValue);\n      expect(getState(\"touched.foo\")).toBeUndefined();\n      expect(getState(\"dirty.foo\")).toBeUndefined();\n    }\n  );\n\n  it.each([\"form\", \"array\"])(\"should run %s-level validation\", async (type) => {\n    const error = \"Required\";\n    const { remove, getState } = renderHelper({\n      defaultValues: { foo: value },\n      formValidate:\n        type === \"form\"\n          ? ({ foo }) => (!foo.length ? { foo: error } : {})\n          : undefined,\n      validate:\n        type === \"array\" ? (val) => (!val.length ? error : false) : undefined,\n    });\n    act(() => {\n      remove(0);\n    });\n    await waitFor(() => expect(getState(\"errors.foo\")).toBe(error));\n  });\n\n  it(\"should not run validation\", () => {\n    const validate = jest.fn();\n    const { remove } = renderHelper({\n      validateOnChange: false,\n      validate,\n    });\n    act(() => {\n      remove(0);\n    });\n    expect(validate).not.toHaveBeenCalled();\n  });\n\n  describe(\"conditional fields\", () => {\n    const initialState = {\n      values: {},\n      touched: {},\n      errors: {},\n      isDirty: false,\n      dirty: {},\n      isValidating: false,\n      isValid: true,\n      isSubmitting: false,\n      isSubmitted: false,\n      submitCount: 0,\n    };\n    const formValue = value;\n    const fieldValue = [{ a: \"🍋\", b: \"🍋\" }];\n\n    it(\"should set form-level default value correctly (FieldArray)\", async () => {\n      const { getState, setError, setTouched, setDirty, setShow } =\n        renderHelper({\n          defaultValues: { foo: formValue },\n          children: ({ show }: API) => <>{show && <FieldArray />}</>,\n        });\n\n      act(() => setShow(true));\n      await waitFor(() => {\n        expect(getState()).toEqual({\n          ...initialState,\n          values: { foo: formValue },\n        });\n        expect((screen.getByTestId(\"foo[0].a\") as HTMLInputElement).value).toBe(\n          formValue[0].a\n        );\n        expect((screen.getByTestId(\"foo[0].b\") as HTMLInputElement).value).toBe(\n          formValue[0].b\n        );\n      });\n\n      act(() => {\n        setError(\"foo\", [{ a: \"Required\", b: \"Required\" }]);\n        setTouched(\"foo[0].a\", true, { shouldValidate: false });\n        setTouched(\"foo[0].b\", true, { shouldValidate: false });\n        setDirty(\"foo[0].a\");\n        setDirty(\"foo[0].b\");\n        setShow(false);\n      });\n      await waitFor(() => expect(getState()).toEqual(initialState));\n\n      act(() => setShow(true));\n      await waitFor(() => {\n        expect(getState()).toEqual({\n          ...initialState,\n          values: {},\n        });\n        expect(screen.queryByRole(\"textbox\")).not.toBeInTheDocument();\n      });\n    });\n\n    it(\"should set array-level default value correctly (FieldArray)\", async () => {\n      const { getState, setError, setTouched, setDirty, setShow } =\n        renderHelper({\n          children: ({ show }: API) => (\n            <>{show && <FieldArray defaultValue={fieldValue} />}</>\n          ),\n        });\n\n      act(() => setShow(true));\n      await waitFor(() => {\n        expect(getState()).toEqual({\n          ...initialState,\n          values: { foo: fieldValue },\n        });\n        expect((screen.getByTestId(\"foo[0].a\") as HTMLInputElement).value).toBe(\n          fieldValue[0].a\n        );\n        expect((screen.getByTestId(\"foo[0].b\") as HTMLInputElement).value).toBe(\n          fieldValue[0].b\n        );\n      });\n\n      act(() => {\n        setError(\"foo\", [{ a: \"Required\", b: \"Required\" }]);\n        setTouched(\"foo[0].a\", true, { shouldValidate: false });\n        setTouched(\"foo[0].b\", true, { shouldValidate: false });\n        setDirty(\"foo[0].a\");\n        setDirty(\"foo[0].b\");\n        setShow(false);\n      });\n      await waitFor(() => expect(getState()).toEqual(initialState));\n\n      act(() => setShow(true));\n      await waitFor(() => {\n        expect(getState()).toEqual({\n          ...initialState,\n          values: { foo: fieldValue },\n        });\n        expect((screen.getByTestId(\"foo[0].a\") as HTMLInputElement).value).toBe(\n          fieldValue[0].a\n        );\n        expect((screen.getByTestId(\"foo[0].b\") as HTMLInputElement).value).toBe(\n          fieldValue[0].b\n        );\n      });\n    });\n\n    it.each([\"form\", \"array\", \"field\"])(\n      \"should set %s-level default value correctly (input/Field)\",\n      async (type) => {\n        const { getState, setError, setTouched, setDirty, setShow } =\n          renderHelper({\n            defaultValues: type === \"form\" ? { foo: formValue } : undefined,\n            defaultValue:\n              // eslint-disable-next-line no-nested-ternary\n              type === \"array\"\n                ? fieldValue\n                : type === \"field\"\n                ? [{}]\n                : undefined,\n            children: ({ fields, show }: API) =>\n              fields.map((name) => (\n                <div key={name}>\n                  {show && (\n                    <input\n                      data-testid={`${name}.a`}\n                      name={`${name}.a`}\n                      defaultValue={\n                        type === \"field\" ? fieldValue[0].a : undefined\n                      }\n                    />\n                  )}\n                  {show && (\n                    <Field\n                      data-testid={`${name}.b`}\n                      name={`${name}.b`}\n                      defaultValue={\n                        type === \"field\" ? fieldValue[0].b : undefined\n                      }\n                    />\n                  )}\n                </div>\n              )),\n          });\n\n        act(() => setShow(true));\n        const state = {\n          ...initialState,\n          values: { foo: type === \"form\" ? formValue : fieldValue },\n        };\n        await waitFor(() => {\n          expect(getState()).toEqual(state);\n          expect(\n            (screen.getByTestId(\"foo[0].a\") as HTMLInputElement).value\n          ).toBe(type === \"form\" ? formValue[0].a : fieldValue[0].a);\n          expect(\n            (screen.getByTestId(\"foo[0].b\") as HTMLInputElement).value\n          ).toBe(type === \"form\" ? formValue[0].b : fieldValue[0].b);\n        });\n\n        act(() => {\n          setError(\"foo\", [{ a: \"Required\", b: \"Required\" }]);\n          setTouched(\"foo[0].a\", true, { shouldValidate: false });\n          setTouched(\"foo[0].b\", true, { shouldValidate: false });\n          setDirty(\"foo[0].a\");\n          setDirty(\"foo[0].b\");\n          setShow(false);\n        });\n        await waitFor(() => expect(getState()).toEqual(initialState));\n\n        act(() => setShow(true));\n        await waitFor(() => {\n          expect(getState()).toEqual(state);\n          expect(\n            (screen.getByTestId(\"foo[0].a\") as HTMLInputElement).value\n          ).toBe(type === \"form\" ? formValue[0].a : fieldValue[0].a);\n          expect(\n            (screen.getByTestId(\"foo[0].b\") as HTMLInputElement).value\n          ).toBe(type === \"form\" ? formValue[0].b : fieldValue[0].b);\n        });\n      }\n    );\n\n    it.each([false, [], () => []])(\n      \"should not remove field (FieldArray)\",\n      async (removeOnUnmounted) => {\n        const { getState, setError, setTouched, setDirty, setShow } =\n          renderHelper({\n            isShow: true,\n            defaultValues: { foo: formValue },\n            removeOnUnmounted,\n            children: ({ show }: API) => <>{show && <FieldArray />}</>,\n          });\n\n        act(() => {\n          setError(\"foo\", [{ a: \"Required\", b: \"Required\" }]);\n          setTouched(\"foo[0].a\", true, { shouldValidate: false });\n          setTouched(\"foo[0].b\", true, { shouldValidate: false });\n          setDirty(\"foo[0].a\");\n          setDirty(\"foo[0].b\");\n          setShow(false);\n        });\n        await waitFor(() =>\n          expect(getState()).toEqual({\n            ...initialState,\n            values: { foo: formValue },\n            errors: { foo: [{ a: \"Required\", b: \"Required\" }] },\n            isValid: false,\n            touched: { foo: [{ a: true, b: true }] },\n            dirty: { foo: [{ a: true, b: true }] },\n            isDirty: true,\n          })\n        );\n\n        act(() => setShow(true));\n        await waitFor(() => {\n          expect(\n            (screen.getByTestId(\"foo[0].a\") as HTMLInputElement).value\n          ).toBe(formValue[0].a);\n          expect(\n            (screen.getByTestId(\"foo[0].b\") as HTMLInputElement).value\n          ).toBe(formValue[0].b);\n        });\n      }\n    );\n\n    it.each([false, [], () => []])(\n      \"should not remove field (input/Field)\",\n      async (removeOnUnmounted) => {\n        const { getState, setError, setTouched, setDirty, setShow } =\n          renderHelper({\n            isShow: true,\n            defaultValues: { foo: formValue },\n            removeOnUnmounted,\n            children: ({ fields, show }: API) =>\n              fields.map((name) => (\n                <div key={name}>\n                  {show && (\n                    <input data-testid={`${name}.a`} name={`${name}.a`} />\n                  )}\n                  {show && (\n                    <Field data-testid={`${name}.b`} name={`${name}.b`} />\n                  )}\n                </div>\n              )),\n          });\n\n        act(() => {\n          setError(\"foo\", [{ a: \"Required\", b: \"Required\" }]);\n          setTouched(\"foo[0].a\", true, { shouldValidate: false });\n          setTouched(\"foo[0].b\", true, { shouldValidate: false });\n          setDirty(\"foo[0].a\");\n          setDirty(\"foo[0].b\");\n          setShow(false);\n        });\n        await Promise.resolve();\n        expect(getState()).toEqual({\n          ...initialState,\n          values: { foo: formValue },\n          errors: { foo: [{ a: \"Required\", b: \"Required\" }] },\n          isValid: false,\n          touched: { foo: [{ a: true, b: true }] },\n          dirty: { foo: [{ a: true, b: true }] },\n          isDirty: true,\n        });\n\n        act(() => setShow(true));\n        await waitFor(() => {\n          expect(\n            (screen.getByTestId(\"foo[0].a\") as HTMLInputElement).value\n          ).toBe(formValue[0].a);\n          expect(\n            (screen.getByTestId(\"foo[0].b\") as HTMLInputElement).value\n          ).toBe(formValue[0].b);\n        });\n      }\n    );\n\n    it.each([true, false])(\"should reset correctly\", async (isShow) => {\n      const defaultValues = { foo: isShow ? [{}] : formValue };\n      const { getState, setShow, setValue, reset } = renderHelper({\n        isShow: !isShow,\n        defaultValues,\n        children: ({ fields, show }: API) =>\n          fields.map((name) => (\n            <div key={name}>\n              {show && (\n                <input\n                  data-testid={`${name}.a`}\n                  name={`${name}.a`}\n                  defaultValue={fieldValue[0].a}\n                />\n              )}\n              {show && (\n                <Field\n                  data-testid={`${name}.b`}\n                  name={`${name}.b`}\n                  defaultValue={fieldValue[0].b}\n                />\n              )}\n            </div>\n          )),\n      });\n      act(() => {\n        setShow(true);\n        setValue(\"foo[0].a\", \"🥝\");\n        setValue(\"foo[0].b\", \"🥝\");\n        reset();\n      });\n      await waitFor(() =>\n        expect(getState(\"foo\")).toEqual(isShow ? fieldValue : formValue)\n      );\n      expect((screen.getByTestId(\"foo[0].a\") as HTMLInputElement).value).toBe(\n        isShow ? fieldValue[0].a : formValue[0].a\n      );\n      expect((screen.getByTestId(\"foo[0].b\") as HTMLInputElement).value).toBe(\n        isShow ? fieldValue[0].b : formValue[0].b\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "src/useFieldArray.ts",
    "content": "import { useCallback, useEffect, useState } from \"react\";\n\nimport {\n  FieldArrayConfig,\n  FieldArrayReturn,\n  FormValues,\n  Insert,\n  Keys,\n  Methods,\n  Move,\n  Push,\n  Remove,\n  StateHandler,\n  Swap,\n} from \"./types\";\nimport * as shared from \"./shared\";\nimport {\n  compact,\n  get,\n  getIsDirty,\n  invariant,\n  isUndefined,\n  set,\n  setValuesAsTrue,\n} from \"./utils\";\n\nexport default <T = any, V extends FormValues = FormValues>(\n  name: string,\n  { formId, defaultValue, validate }: FieldArrayConfig<T, V> = {}\n): FieldArrayReturn<T> => {\n  const methods: Methods<V> = shared.get(formId);\n\n  invariant(\n    !methods,\n    '💡 react-cool-form > useFieldArray: It must work with an \"useForm\" hook. See: https://react-cool-form.netlify.app/docs/api-reference/use-form'\n  );\n\n  const {\n    validateOnChange,\n    shouldRemoveField,\n    initialStateRef,\n    fieldArrayRef,\n    fieldValidatorsRef,\n    getState,\n    setDefaultValue,\n    setNodesOrValues,\n    setStateRef,\n    runValidation,\n    removeField,\n  } = methods;\n\n  const getFields = useCallback(\n    (init = false) => {\n      let fields = getState(name);\n\n      if (init && isUndefined(fields)) fields = defaultValue;\n\n      return Array.isArray(fields)\n        ? fields.map((_, index) => `${name}[${index}]`)\n        : [];\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [getState, name]\n  );\n\n  const [fields, setFields] = useState(getFields(true));\n\n  const updateFields = useCallback(() => {\n    setFields(getFields());\n    setNodesOrValues(getState(\"values\"), {\n      shouldSetValues: false,\n      fields: Object.keys(fieldArrayRef.current[name].fields),\n    });\n  }, [fieldArrayRef, getFields, getState, name, setNodesOrValues]);\n\n  useEffect(() => {\n    if (\n      isUndefined(get(initialStateRef.current.values, name)) &&\n      !isUndefined(defaultValue)\n    ) {\n      setDefaultValue(name, defaultValue, true);\n      updateFields();\n    }\n\n    return () => {\n      if (shouldRemoveField(name)) removeField(name);\n    };\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []);\n\n  if (!fieldArrayRef.current[name])\n    fieldArrayRef.current[name] = {\n      reset: updateFields,\n      fields: {},\n    };\n  if (validate) fieldValidatorsRef.current[name] = validate;\n\n  const setState = useCallback(\n    (\n      handler: StateHandler,\n      {\n        shouldTouched,\n        shouldDirty,\n      }: { shouldTouched?: boolean; shouldDirty?: boolean } = {}\n    ) => {\n      let state = getState();\n\n      ([\"values\", \"touched\", \"errors\", \"dirty\"] as Keys[]).forEach((key) => {\n        const value = state[key][name];\n        const fieldsLength = state.values[name]?.length;\n\n        if (\n          key === \"values\" ||\n          (key === \"touched\" && shouldTouched) ||\n          (key === \"dirty\" && shouldDirty) ||\n          !isUndefined(value)\n        )\n          state = set(\n            state,\n            key,\n            {\n              ...state[key],\n              [name]: handler(\n                Array.isArray(value) ? [...value] : [],\n                key,\n                fieldsLength ? fieldsLength - 1 : 0\n              ),\n            },\n            true\n          );\n      });\n\n      setStateRef(\"\", { ...state, shouldDirty: getIsDirty(state.dirty) });\n      updateFields();\n\n      if (validateOnChange) runValidation(name);\n    },\n    [getState, name, runValidation, setStateRef, updateFields, validateOnChange]\n  );\n\n  const push = useCallback<Push<T>>(\n    (value, { shouldTouched, shouldDirty = true } = {}) => {\n      const handler: StateHandler = (f, type, lastIndex = 0) => {\n        if (type === \"values\") {\n          f.push(value);\n        } else if (\n          (type === \"touched\" && shouldTouched) ||\n          (type === \"dirty\" && shouldDirty)\n        ) {\n          f[lastIndex] = setValuesAsTrue(value);\n        }\n\n        return f;\n      };\n\n      setState(handler, { shouldTouched, shouldDirty });\n    },\n    [setState]\n  );\n\n  const insert = useCallback<Insert<T>>(\n    (index, value, { shouldTouched, shouldDirty = true } = {}) => {\n      const handler: StateHandler = (f, type) => {\n        if (type === \"values\") {\n          f.splice(index, 0, value);\n        } else if (\n          (type === \"touched\" && shouldTouched) ||\n          (type === \"dirty\" && shouldDirty)\n        ) {\n          f[index] = setValuesAsTrue(value);\n        } else if (index < f.length) {\n          f.splice(index, 0, undefined);\n        }\n\n        return f;\n      };\n\n      setState(handler, { shouldTouched, shouldDirty });\n    },\n    [setState]\n  );\n\n  const remove = useCallback<Remove<T>>(\n    (index) => {\n      const handler: StateHandler = (f) => {\n        f.splice(index, 1);\n        return compact(f).length ? f : [];\n      };\n      const value = (getState(name) || [])[index];\n\n      setState(handler);\n\n      return value;\n    },\n    [getState, name, setState]\n  );\n\n  const swap = useCallback<Swap>(\n    (indexA, indexB) => {\n      const handler: StateHandler = (f) => {\n        [f[indexA], f[indexB]] = [f[indexB], f[indexA]];\n        return f;\n      };\n\n      setState(handler);\n    },\n    [setState]\n  );\n\n  const move = useCallback<Move>(\n    (from, to) => {\n      const handler: StateHandler = (f) => {\n        f.splice(to, 0, f.splice(from, 1)[0]);\n        return f;\n      };\n\n      setState(handler);\n    },\n    [setState]\n  );\n\n  return [fields, { push, insert, remove, swap, move }];\n};\n"
  },
  {
    "path": "src/useForm.test.tsx",
    "content": "/* eslint-disable react/no-unused-prop-types */\n\nimport { Dispatch, useState } from \"react\";\nimport {\n  render,\n  fireEvent,\n  waitFor,\n  screen,\n  act,\n} from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\n\nimport { FormConfig, FormMethods, SubmitHandler, ErrorHandler } from \"./types\";\nimport { set, remove } from \"./shared\";\nimport { isFunction } from \"./utils\";\nimport useForm from \"./useForm\";\n\njest.mock(\"./shared\", () => ({ set: jest.fn(), remove: jest.fn() }));\n\ntype Children = JSX.Element | JSX.Element[] | null;\n\ntype API = Omit<FormMethods, \"form\"> & {\n  show: boolean;\n  setShow: Dispatch<boolean>;\n};\n\ninterface Config extends FormConfig {\n  children: Children | ((api: API) => Children);\n  isShow: boolean;\n  onSubmit: (values: any) => void;\n  onSubmitFull: SubmitHandler;\n  onError: (errors: any) => void;\n  onErrorFull: ErrorHandler;\n  onRender: () => void;\n}\n\ntype Props = Partial<Config>;\n\nconst Form = ({\n  children,\n  isShow,\n  onSubmit = () => null,\n  onSubmitFull,\n  onError = () => null,\n  onErrorFull,\n  onRender = () => null,\n  ...config\n}: Props) => {\n  const [show, setShow] = useState(!!isShow);\n  const methods = useForm({\n    ...config,\n    onSubmit: (...args) =>\n      onSubmitFull ? onSubmitFull(...args) : onSubmit(args[0]),\n    onError: (...args) =>\n      onErrorFull ? onErrorFull(...args) : onError(args[0]),\n  });\n\n  onRender();\n\n  return (\n    <form data-testid=\"form\" ref={methods.form}>\n      {isFunction(children)\n        ? children({ ...methods, show, setShow })\n        : children}\n    </form>\n  );\n};\n\nconst renderHelper = ({ children = null, ...rest }: Props = {}) => {\n  let api: API;\n\n  const { unmount } = render(\n    <Form {...rest}>\n      {(a) => {\n        api = a;\n        return isFunction(children) ? children(a) : children;\n      }}\n    </Form>\n  );\n\n  // @ts-expect-error\n  return { unmount, ...api };\n};\n\ndescribe(\"useForm\", () => {\n  console.warn = jest.fn();\n  const onSubmit = jest.fn();\n  const onError = jest.fn();\n  const onReset = jest.fn();\n  const onRender = jest.fn();\n  const builtInError = \"Constraints not satisfied\";\n  const initialState = {\n    values: {},\n    touched: {},\n    errors: {},\n    isDirty: false,\n    dirty: {},\n    isValidating: false,\n    isValid: true,\n    isSubmitting: false,\n    isSubmitted: false,\n    submitCount: 0,\n  };\n  const options = {\n    focus: expect.any(Function),\n    removeField: expect.any(Function),\n    getState: expect.any(Function),\n    setValue: expect.any(Function),\n    setTouched: expect.any(Function),\n    setDirty: expect.any(Function),\n    setError: expect.any(Function),\n    clearErrors: expect.any(Function),\n    runValidation: expect.any(Function),\n    reset: expect.any(Function),\n    submit: expect.any(Function),\n  };\n\n  beforeEach(() => {\n    jest.clearAllMocks();\n    // @ts-expect-error\n    global.__DEV__ = true;\n  });\n\n  describe(\"warning\", () => {\n    it(\"should warn for a missing name field\", () => {\n      renderHelper({ children: <input /> });\n      expect(console.warn).toHaveBeenCalledWith(\n        '💡 react-cool-form > field: Missing \"name\" attribute. Do you want to exclude the field? See: https://react-cool-form.netlify.app/docs/api-reference/use-form/#excludefields'\n      );\n    });\n\n    it(\"should not warn for a missing name field\", () => {\n      renderHelper({ children: <input name=\"foo\" /> });\n      expect(console.warn).not.toHaveBeenCalled();\n    });\n\n    it(\"should not warn for a missing name field when it's excluded\", () => {\n      renderHelper({ children: <input data-testid=\"foo\" data-rcf-exclude /> });\n      expect(console.warn).not.toHaveBeenCalled();\n\n      fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"🍎\" } });\n      expect(console.warn).not.toHaveBeenCalled();\n    });\n\n    it('should warn watch \"values\" alone', () => {\n      const { use } = renderHelper();\n      use(\"values\");\n      use(\"values\");\n      expect(console.warn).toHaveBeenCalledTimes(1);\n      expect(console.warn).toHaveBeenCalledWith(\n        '💡 react-cool-form > use: Getting \"values\" alone might cause unnecessary re-renders. If you know what you\\'re doing, just ignore this warning. See: https://react-cool-form.netlify.app/docs/getting-started/form-state#best-practices'\n      );\n    });\n\n    it('should not warn watch \"values\" alone', () => {\n      const { use } = renderHelper();\n      use(\"foo\");\n      expect(console.warn).not.toHaveBeenCalled();\n    });\n\n    it(\"should warn form-level validation exception\", async () => {\n      renderHelper({\n        validate: () => {\n          // eslint-disable-next-line no-throw-literal\n          throw \"🍎\";\n        },\n        children: <input data-testid=\"foo\" name=\"foo\" />,\n      });\n      fireEvent.input(screen.getByTestId(\"foo\"));\n      await waitFor(() =>\n        expect(console.warn).toHaveBeenCalledWith(\n          \"💡 react-cool-form > validate form: \",\n          \"🍎\"\n        )\n      );\n    });\n\n    it(\"should warn field-level validation exception\", async () => {\n      const id = \"foo\";\n      renderHelper({\n        children: ({ field }: API) => (\n          <input\n            data-testid={id}\n            name=\"foo\"\n            ref={field(() => {\n              // eslint-disable-next-line no-throw-literal\n              throw \"🍎\";\n            })}\n          />\n        ),\n      });\n      fireEvent.input(screen.getByTestId(id));\n      await waitFor(() =>\n        expect(console.warn).toHaveBeenCalledWith(\n          `💡 react-cool-form > validate ${id}: `,\n          \"🍎\"\n        )\n      );\n    });\n\n    it(\"should not warn in production\", () => {\n      // @ts-expect-error\n      global.__DEV__ = false;\n      renderHelper({ children: <input /> });\n      expect(console.warn).not.toHaveBeenCalled();\n    });\n  });\n\n  it(\"should return methods correctly\", () => {\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    const { unmount, show, setShow, ...methods } = renderHelper();\n    expect(methods).toEqual({\n      form: expect.any(Function),\n      field: expect.any(Function),\n      use: expect.any(Function),\n      focus: expect.any(Function),\n      removeField: expect.any(Function),\n      getState: expect.any(Function),\n      setValue: expect.any(Function),\n      setTouched: expect.any(Function),\n      setDirty: expect.any(Function),\n      setError: expect.any(Function),\n      clearErrors: expect.any(Function),\n      runValidation: expect.any(Function),\n      reset: expect.any(Function),\n      submit: expect.any(Function),\n    });\n  });\n\n  it(\"should handle global methods correctly\", () => {\n    const { unmount } = renderHelper();\n    expect(set).toHaveBeenCalled();\n    unmount();\n    expect(remove).toHaveBeenCalled();\n  });\n\n  describe(\"event callbacks\", () => {\n    it('should call \"onSubmit\" event correctly', async () => {\n      const { getState } = renderHelper({\n        onSubmitFull: onSubmit,\n        onError,\n        children: (\n          <>\n            <input data-testid=\"foo\" name=\"foo\" />\n            <input data-testid=\"bar\" name=\"bar\" />\n          </>\n        ),\n      });\n\n      const value = \"🍎\";\n      fireEvent.input(screen.getByTestId(\"foo\"), { target: { value } });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      const state = {\n        ...initialState,\n        values: { foo: value, bar: \"\" },\n        touched: { foo: true, bar: true },\n        dirty: { foo: true },\n        isDirty: true,\n        isValidating: true,\n        isSubmitting: true,\n        submitCount: 1,\n      };\n      expect(getState()).toEqual(state);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith(\n          state.values,\n          options,\n          expect.any(Object)\n        )\n      );\n      expect(onError).not.toHaveBeenCalled();\n      expect(getState()).toEqual({\n        ...state,\n        isValidating: false,\n        isSubmitting: false,\n        isSubmitted: true,\n      });\n\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      expect(getState(\"isSubmitted\")).toBeFalsy();\n      await waitFor(() => expect(onSubmit).toHaveBeenCalled());\n      expect(getState(\"isSubmitted\")).toBeTruthy();\n    });\n\n    it('should call \"onError\" event correctly', async () => {\n      const { getState } = renderHelper({\n        onErrorFull: onError,\n        onSubmit,\n        children: <input data-testid=\"foo\" name=\"foo\" required />,\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      const errors = { foo: builtInError };\n      await waitFor(() =>\n        expect(onError).toHaveBeenCalledWith(\n          errors,\n          options,\n          expect.any(Object)\n        )\n      );\n      expect(onSubmit).not.toHaveBeenCalled();\n      expect(getState()).toEqual({\n        ...initialState,\n        values: { foo: \"\" },\n        errors,\n        touched: { foo: true },\n        isValid: false,\n        submitCount: 1,\n      });\n    });\n\n    it('should call \"onReset\" event correctly', () => {\n      const defaultValues = { foo: \"\" };\n      const { getState } = renderHelper({\n        defaultValues,\n        onReset,\n        children: <input data-testid=\"foo\" name=\"foo\" />,\n      });\n      const value = \"🍎\";\n      const foo = screen.getByTestId(\"foo\") as HTMLInputElement;\n      fireEvent.input(foo, { target: { value } });\n      expect(foo.value).toBe(value);\n      fireEvent.reset(screen.getByTestId(\"form\"));\n      expect(foo.value).toBe(defaultValues.foo);\n      expect(onReset).toHaveBeenCalledWith(\n        defaultValues,\n        options,\n        expect.any(Object)\n      );\n      expect(getState()).toEqual({ ...initialState, values: defaultValues });\n    });\n  });\n\n  describe(\"submit\", () => {\n    it(\"should submit form with success mode\", async () => {\n      const { submit, getState } = renderHelper({\n        onSubmitFull: onSubmit,\n        children: (\n          <>\n            <input data-testid=\"foo\" name=\"foo\" />\n            <input data-testid=\"bar\" name=\"bar\" />\n          </>\n        ),\n      });\n      const value = \"🍎\";\n      const e = {};\n      fireEvent.input(screen.getByTestId(\"foo\"), { target: { value } });\n      // @ts-expect-error\n      const result = await submit(e);\n      const values = { foo: value, bar: \"\" };\n      expect(result).toEqual({ values });\n      expect(onSubmit).toHaveBeenCalledWith(values, options, e);\n      expect(getState()).toEqual({\n        ...initialState,\n        values,\n        touched: { foo: true, bar: true },\n        dirty: { foo: true },\n        isDirty: true,\n        isSubmitted: true,\n        submitCount: 1,\n      });\n    });\n\n    it(\"should submit form with fail mode\", async () => {\n      const { submit, getState } = renderHelper({\n        onErrorFull: onError,\n        children: <input data-testid=\"foo\" name=\"foo\" required />,\n      });\n      const e = {};\n      // @ts-expect-error\n      const result = await submit(e);\n      const errors = { foo: builtInError };\n      expect(result).toEqual({ errors });\n      expect(onError).toHaveBeenCalledWith(errors, options, e);\n      expect(getState()).toEqual({\n        ...initialState,\n        values: { foo: \"\" },\n        errors,\n        touched: { foo: true },\n        isValid: false,\n        submitCount: 1,\n      });\n    });\n\n    it(\"should focus on error\", async () => {\n      renderHelper({\n        onError,\n        children: (\n          <>\n            <input data-testid=\"foo\" name=\"foo\" required />\n            <input data-testid=\"bar\" name=\"bar\" required />\n          </>\n        ),\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onError).toHaveBeenCalled());\n      expect(screen.getByTestId(\"foo\")).toHaveFocus();\n\n      fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"🍎\" } });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onError).toHaveBeenCalled());\n      expect(screen.getByTestId(\"bar\")).toHaveFocus();\n    });\n\n    it.each([false, []])(\n      \"should disable focus on error\",\n      async (focusOnError) => {\n        renderHelper({\n          focusOnError,\n          onError,\n          children: <input data-testid=\"foo\" name=\"foo\" required />,\n        });\n        fireEvent.submit(screen.getByTestId(\"form\"));\n        await waitFor(() => expect(onError).toHaveBeenCalled());\n        expect(screen.getByTestId(\"foo\")).not.toHaveFocus();\n      }\n    );\n\n    it.each([\n      [\"bar\", \"foo\"],\n      // eslint-disable-next-line no-return-assign\n      (names: string[]) => ([names[0], names[1]] = [names[1], names[0]]),\n    ])(\"should focus on error by custom order\", async (focusOnError) => {\n      renderHelper({\n        focusOnError,\n        onError,\n        children: (\n          <>\n            <input data-testid=\"foo\" name=\"foo\" required />\n            <input data-testid=\"bar\" name=\"bar\" required />\n          </>\n        ),\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onError).toHaveBeenCalled());\n      expect(screen.getByTestId(\"bar\")).toHaveFocus();\n    });\n  });\n\n  it(\"should reset form correctly\", () => {\n    const defaultValues = { foo: \"\" };\n    const { reset, setValue, setError, getState } = renderHelper({\n      defaultValues,\n      onReset,\n      children: <input data-testid=\"foo\" name=\"foo\" />,\n    });\n    const value = \"🍎\";\n    const foo = screen.getByTestId(\"foo\") as HTMLInputElement;\n\n    setValue(\"foo\", value);\n    setError(\"foo\", \"Required\");\n    const e = {};\n    // @ts-expect-error\n    act(() => reset(null, null, e));\n    expect(foo.value).toBe(defaultValues.foo);\n    expect(onReset).toHaveBeenCalledWith(defaultValues, options, e);\n    expect(getState()).toEqual({ ...initialState, values: defaultValues });\n\n    const values = { foo: value };\n    // @ts-expect-error\n    act(() => reset(values, null, e));\n    expect(foo.value).toBe(values.foo);\n    expect(onReset).toHaveBeenCalledWith(values, options, e);\n    expect(getState()).toEqual({ ...initialState, values });\n\n    // @ts-expect-error\n    act(() => reset((prevValues) => ({ ...prevValues, ...values }), null, e));\n    expect(foo.value).toBe(value);\n    expect(onReset).toHaveBeenCalledWith(values, options, e);\n    expect(getState()).toEqual({ ...initialState, values });\n\n    const error = \"Required\";\n    setValue(\"foo\", value);\n    setError(\"foo\", error);\n    // @ts-expect-error\n    act(() => reset(null, [\"values\", \"errors\", \"touched\"], e));\n    expect(foo.value).toBe(value);\n    expect(onReset).toHaveBeenCalledWith(values, options, e);\n    expect(getState()).toEqual({\n      ...initialState,\n      values,\n      errors: { foo: error },\n      touched: { foo: true },\n    });\n  });\n\n  describe(\"default values\", () => {\n    const defaultValues = {\n      text: \"🍎\",\n      number: 1,\n      range: 10,\n      checkbox: true,\n      checkboxes: [\"🍎\"],\n      radio: \"🍎\",\n      textarea: \"🍎\",\n      select: \"🍎\",\n      selects: [\"🍎\", \"🍋\"],\n    };\n    const defaultNestedValue = { text: { a: [{ b: \"🍎\" }] } };\n    const getChildren = () => (\n      <>\n        <input data-testid=\"text\" name=\"text\" />\n        <input data-testid=\"number\" name=\"number\" type=\"number\" />\n        <input data-testid=\"range\" name=\"range\" type=\"range\" />\n        <input data-testid=\"checkbox\" name=\"checkbox\" type=\"checkbox\" />\n        <input\n          data-testid=\"checkboxes-0\"\n          name=\"checkboxes\"\n          type=\"checkbox\"\n          value=\"🍎\"\n        />\n        <input\n          data-testid=\"checkboxes-1\"\n          name=\"checkboxes\"\n          type=\"checkbox\"\n          value=\"🍋\"\n        />\n        <input data-testid=\"radio-0\" name=\"radio\" type=\"radio\" value=\"🍎\" />\n        <input data-testid=\"radio-1\" name=\"radio\" type=\"radio\" value=\"🍋\" />\n        <textarea data-testid=\"textarea\" name=\"textarea\" />\n        <select name=\"select\">\n          <option data-testid=\"select-0\" value=\"🍎\">\n            🍎\n          </option>\n          <option data-testid=\"select-1\" value=\"🍋\">\n            🍋\n          </option>\n        </select>\n        <select name=\"selects\" multiple>\n          <option data-testid=\"selects-0\" value=\"🍎\">\n            🍎\n          </option>\n          <option data-testid=\"selects-1\" value=\"🍋\">\n            🍋\n          </option>\n        </select>\n      </>\n    );\n\n    it(\"should get empty values\", async () => {\n      renderHelper({ onSubmit });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({}));\n    });\n\n    it(\"should set values correctly via value attribute\", async () => {\n      renderHelper({ onSubmit, children: getChildren() });\n      const values: any = {\n        text: \"\",\n        number: \"\",\n        range: 50,\n        checkbox: false,\n        checkboxes: [],\n        radio: \"\",\n        textarea: \"\",\n        select: \"🍎\",\n        selects: [],\n      };\n      const {\n        text,\n        number,\n        range,\n        checkbox,\n        checkboxes,\n        radio,\n        textarea,\n        select,\n        selects,\n      } = values;\n\n      expect((screen.getByTestId(\"text\") as HTMLInputElement).value).toBe(text);\n      expect((screen.getByTestId(\"number\") as HTMLInputElement).value).toBe(\n        number.toString()\n      );\n      expect((screen.getByTestId(\"range\") as HTMLInputElement).value).toBe(\n        range.toString()\n      );\n      // eslint-disable-next-line jest-dom/prefer-checked\n      expect((screen.getByTestId(\"checkbox\") as HTMLInputElement).checked).toBe(\n        checkbox\n      );\n      const checkboxes0 = screen.getByTestId(\n        \"checkboxes-0\"\n      ) as HTMLInputElement;\n      expect(checkboxes0.checked).toBe(checkboxes.includes(checkboxes0.value));\n      const checkboxes1 = screen.getByTestId(\n        \"checkboxes-1\"\n      ) as HTMLInputElement;\n      expect(checkboxes1.checked).toBe(checkboxes.includes(checkboxes1.value));\n      expect((screen.getByTestId(\"textarea\") as HTMLInputElement).value).toBe(\n        textarea\n      );\n      const radio0 = screen.getByTestId(\"radio-0\") as HTMLInputElement;\n      expect(radio0.checked).toBe(radio0.value === radio);\n      const radio1 = screen.getByTestId(\"radio-0\") as HTMLInputElement;\n      expect(radio1.checked).toBe(radio1.value === radio);\n      const select0 = screen.getByTestId(\"select-0\") as HTMLOptionElement;\n      expect(select0.selected).toBe(select0.value === select);\n      const select1 = screen.getByTestId(\"select-1\") as HTMLOptionElement;\n      expect(select1.selected).toBe(select1.value === select);\n      const selects0 = screen.getByTestId(\"selects-0\") as HTMLOptionElement;\n      expect(selects0.selected).toBe(selects.includes(selects0.value));\n      const selects1 = screen.getByTestId(\"selects-1\") as HTMLOptionElement;\n      expect(selects1.selected).toBe(selects.includes(selects1.value));\n\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onSubmit).toHaveBeenCalledWith(values));\n    });\n\n    it(\"should set values correctly via defaultValues option\", async () => {\n      renderHelper({\n        defaultValues,\n        onSubmit,\n        children: getChildren(),\n      });\n      const {\n        text,\n        number,\n        range,\n        checkbox,\n        checkboxes,\n        radio,\n        textarea,\n        select,\n        selects,\n      } = defaultValues;\n\n      expect((screen.getByTestId(\"text\") as HTMLInputElement).value).toBe(text);\n      expect((screen.getByTestId(\"number\") as HTMLInputElement).value).toBe(\n        number.toString()\n      );\n      expect((screen.getByTestId(\"range\") as HTMLInputElement).value).toBe(\n        range.toString()\n      );\n      // eslint-disable-next-line jest-dom/prefer-checked\n      expect((screen.getByTestId(\"checkbox\") as HTMLInputElement).checked).toBe(\n        checkbox\n      );\n      const checkboxes0 = screen.getByTestId(\n        \"checkboxes-0\"\n      ) as HTMLInputElement;\n      expect(checkboxes0.checked).toBe(checkboxes.includes(checkboxes0.value));\n      const checkboxes1 = screen.getByTestId(\n        \"checkboxes-1\"\n      ) as HTMLInputElement;\n      expect(checkboxes1.checked).toBe(checkboxes.includes(checkboxes1.value));\n      const radio0 = screen.getByTestId(\"radio-0\") as HTMLInputElement;\n      expect(radio0.checked).toBe(radio0.value === radio);\n      const radio1 = screen.getByTestId(\"radio-0\") as HTMLInputElement;\n      expect(radio1.checked).toBe(radio1.value === radio);\n      expect((screen.getByTestId(\"textarea\") as HTMLInputElement).value).toBe(\n        textarea\n      );\n      const select0 = screen.getByTestId(\"select-0\") as HTMLOptionElement;\n      expect(select0.selected).toBe(select0.value === select);\n      const select1 = screen.getByTestId(\"select-1\") as HTMLOptionElement;\n      expect(select1.selected).toBe(select1.value === select);\n      const selects0 = screen.getByTestId(\"selects-0\") as HTMLOptionElement;\n      expect(selects0.selected).toBe(selects.includes(selects0.value));\n      const selects1 = screen.getByTestId(\"selects-1\") as HTMLOptionElement;\n      expect(selects1.selected).toBe(selects.includes(selects1.value));\n\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onSubmit).toHaveBeenCalledWith(defaultValues));\n    });\n\n    it(\"should set nested values correctly via defaultValues option\", async () => {\n      renderHelper({\n        defaultValues: defaultNestedValue,\n        onSubmit,\n        children: <input data-testid=\"text\" name=\"text.a[0].b\" />,\n      });\n\n      expect((screen.getByTestId(\"text\") as HTMLInputElement).value).toBe(\n        defaultNestedValue.text.a[0].b\n      );\n\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith(defaultNestedValue)\n      );\n    });\n\n    it(\"should set values correctly via defaultValue attribute\", async () => {\n      renderHelper({\n        onSubmit,\n        children: (\n          <>\n            <input name=\"text\" defaultValue={defaultValues.text} />\n            <input\n              name=\"number\"\n              type=\"number\"\n              defaultValue={defaultValues.number}\n            />\n            <input\n              name=\"range\"\n              type=\"range\"\n              defaultValue={defaultValues.range}\n            />\n            <input name=\"checkbox\" type=\"checkbox\" defaultChecked />\n            <input\n              name=\"checkboxes\"\n              type=\"checkbox\"\n              value=\"🍎\"\n              defaultChecked\n            />\n            <input name=\"checkboxes\" type=\"checkbox\" value=\"🍋\" />\n            <input name=\"radio\" type=\"radio\" value=\"🍎\" defaultChecked />\n            <input name=\"radio\" type=\"radio\" value=\"🍋\" />\n            <textarea name=\"textarea\" defaultValue={defaultValues.textarea} />\n            <select name=\"select\" defaultValue={defaultValues.select}>\n              <option value=\"🍎\">🍎</option>\n              <option value=\"🍋\">🍋</option>\n            </select>\n            <select\n              name=\"selects\"\n              multiple\n              defaultValue={defaultValues.selects}\n            >\n              <option value=\"🍎\">🍎</option>\n              <option value=\"🍋\">🍋</option>\n            </select>\n          </>\n        ),\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onSubmit).toHaveBeenCalledWith(defaultValues));\n    });\n\n    it(\"should set nested values correctly via defaultValue attribute\", async () => {\n      renderHelper({\n        onSubmit,\n        children: (\n          <input\n            name=\"text.a[0].b\"\n            defaultValue={defaultNestedValue.text.a[0].b}\n          />\n        ),\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith(defaultNestedValue)\n      );\n    });\n\n    it(\"should use form-level default value first\", async () => {\n      const value = \"🍎\";\n      renderHelper({\n        defaultValues: { foo: value },\n        onSubmit,\n        children: <input data-testid=\"foo\" name=\"foo\" defaultValue=\"🍋\" />,\n      });\n      expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(value);\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: value })\n      );\n    });\n  });\n\n  describe(\"handle change\", () => {\n    it.each([\"text\", \"number\", \"range\"])(\n      \"should handle %s correctly\",\n      async (type) => {\n        const defaultValues: any = {\n          text: \"\",\n          number: \"\",\n          range: 50,\n        };\n        const { getState } = renderHelper({\n          defaultValues: { foo: defaultValues[type] },\n          onSubmit,\n          children: <input data-testid=\"foo\" name=\"foo\" type={type} />,\n        });\n        const values: any = {\n          text: \"🍎\",\n          number: 100,\n          range: 100,\n        };\n        fireEvent.input(screen.getByTestId(\"foo\"), {\n          target: { value: values[type] },\n        });\n        fireEvent.submit(screen.getByTestId(\"form\"));\n        await waitFor(() =>\n          expect(onSubmit).toHaveBeenCalledWith({ foo: values[type] })\n        );\n        expect(getState(\"touched.foo\")).toBeTruthy();\n        expect(getState(\"dirty.foo\")).toBeTruthy();\n        expect(getState(\"isDirty\")).toBeTruthy();\n\n        fireEvent.input(screen.getByTestId(\"foo\"), {\n          target: { value: defaultValues[type] },\n        });\n        fireEvent.submit(screen.getByTestId(\"form\"));\n        await waitFor(() =>\n          expect(onSubmit).toHaveBeenCalledWith({ foo: defaultValues[type] })\n        );\n        expect(getState(\"dirty.foo\")).toBeUndefined();\n        expect(getState(\"isDirty\")).toBeFalsy();\n      }\n    );\n\n    it(\"should handle checkbox with boolean correctly\", async () => {\n      const { getState } = renderHelper({\n        defaultValues: { foo: false },\n        onSubmit,\n        children: <input data-testid=\"foo\" name=\"foo\" type=\"checkbox\" />,\n      });\n      const foo = screen.getByTestId(\"foo\") as HTMLInputElement;\n      const form = screen.getByTestId(\"form\");\n\n      userEvent.click(foo);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: foo.checked })\n      );\n      expect(getState(\"touched.foo\")).toBeTruthy();\n      expect(getState(\"dirty.foo\")).toBeTruthy();\n      expect(getState(\"isDirty\")).toBeTruthy();\n\n      userEvent.click(foo);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: foo.checked })\n      );\n      expect(getState(\"dirty.foo\")).toBeUndefined();\n      expect(getState(\"isDirty\")).toBeFalsy();\n    });\n\n    it.each([\"valid\", \"invalid\"])(\n      \"should handle checkbox with array correctly\",\n      async (type) => {\n        const value = \"🍎\";\n        renderHelper({\n          onSubmit,\n          children: (\n            <input\n              data-testid=\"foo\"\n              name=\"foo\"\n              type=\"checkbox\"\n              defaultValue={type === \"valid\" ? value : undefined}\n            />\n          ),\n        });\n        const foo = screen.getByTestId(\"foo\") as HTMLInputElement;\n        const form = screen.getByTestId(\"form\");\n\n        userEvent.click(foo);\n        fireEvent.submit(form);\n        await waitFor(() =>\n          expect(onSubmit).toHaveBeenCalledWith({\n            foo: type === \"valid\" ? [value] : foo.checked,\n          })\n        );\n\n        userEvent.click(foo);\n        fireEvent.submit(form);\n        await waitFor(() =>\n          expect(onSubmit).toHaveBeenCalledWith({\n            foo: type === \"valid\" ? [] : foo.checked,\n          })\n        );\n      }\n    );\n\n    it(\"should handle checkboxes correctly\", async () => {\n      const { getState } = renderHelper({\n        defaultValues: { foo: [] },\n        onSubmit,\n        children: (\n          <>\n            <input data-testid=\"foo-0\" name=\"foo\" type=\"checkbox\" value=\"🍎\" />\n            <input data-testid=\"foo-1\" name=\"foo\" type=\"checkbox\" value=\"🍋\" />\n          </>\n        ),\n      });\n      const form = screen.getByTestId(\"form\");\n      const foo0 = screen.getByTestId(\"foo-0\") as HTMLInputElement;\n      const foo1 = screen.getByTestId(\"foo-1\") as HTMLInputElement;\n\n      userEvent.click(foo0);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: [foo0.value] })\n      );\n      expect(getState(\"touched.foo\")).toBeTruthy();\n      expect(getState(\"dirty.foo\")).toBeTruthy();\n      expect(getState(\"isDirty\")).toBeTruthy();\n\n      userEvent.click(foo1);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: [foo0.value, foo1.value] })\n      );\n\n      userEvent.click(foo0);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: [foo1.value] })\n      );\n\n      userEvent.click(foo1);\n      fireEvent.submit(form);\n      await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ foo: [] }));\n      expect(getState(\"dirty.foo\")).toBeUndefined();\n      expect(getState(\"isDirty\")).toBeFalsy();\n    });\n\n    it(\"should handle radio buttons correctly\", async () => {\n      renderHelper({\n        defaultValues: { foo: \"\" },\n        onSubmit,\n        children: (\n          <>\n            <input data-testid=\"foo-0\" name=\"foo\" type=\"radio\" value=\"🍎\" />\n            <input data-testid=\"foo-1\" name=\"foo\" type=\"radio\" value=\"🍋\" />\n          </>\n        ),\n      });\n      const form = screen.getByTestId(\"form\");\n      const foo0 = screen.getByTestId(\"foo-0\") as HTMLInputElement;\n      const foo1 = screen.getByTestId(\"foo-1\") as HTMLInputElement;\n\n      userEvent.click(foo0);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: foo0.value })\n      );\n\n      userEvent.click(foo1);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: foo1.value })\n      );\n    });\n\n    it(\"should handle textarea correctly\", async () => {\n      renderHelper({\n        defaultValues: { foo: \"\" },\n        onSubmit,\n        children: <textarea data-testid=\"foo\" name=\"foo\" />,\n      });\n      const value = \"🍎\";\n      fireEvent.input(screen.getByTestId(\"foo\"), {\n        target: { value },\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: value })\n      );\n    });\n\n    it(\"should handle select correctly\", async () => {\n      renderHelper({\n        defaultValues: { foo: \"🍎\" },\n        onSubmit,\n        children: (\n          <>\n            <select data-testid=\"foo\" name=\"foo\">\n              <option data-testid=\"foo-0\" value=\"🍎\">\n                🍎\n              </option>\n              <option data-testid=\"foo-1\" value=\"🍋\">\n                🍋\n              </option>\n            </select>\n          </>\n        ),\n      });\n      const form = screen.getByTestId(\"form\");\n      const foo = screen.getByTestId(\"foo\");\n      const foo0 = screen.getByTestId(\"foo-0\") as HTMLOptionElement;\n      const foo1 = screen.getByTestId(\"foo-1\") as HTMLOptionElement;\n\n      userEvent.selectOptions(foo, [foo1.value]);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: foo1.value })\n      );\n\n      userEvent.selectOptions(foo, [foo0.value]);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: foo0.value })\n      );\n    });\n\n    it(\"should handle multiple select correctly\", async () => {\n      renderHelper({\n        defaultValues: { foo: [] },\n        onSubmit,\n        children: (\n          <>\n            <select data-testid=\"foo\" name=\"foo\" multiple>\n              <option data-testid=\"foo-0\" value=\"🍎\">\n                🍎\n              </option>\n              <option data-testid=\"foo-1\" value=\"🍋\">\n                🍋\n              </option>\n            </select>\n          </>\n        ),\n      });\n      const form = screen.getByTestId(\"form\");\n      const foo = screen.getByTestId(\"foo\");\n      const foo0 = screen.getByTestId(\"foo-0\") as HTMLOptionElement;\n      const foo1 = screen.getByTestId(\"foo-1\") as HTMLOptionElement;\n\n      let value = [foo0.value];\n      userEvent.selectOptions(foo, value);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: value })\n      );\n\n      value = [foo0.value, foo1.value];\n      userEvent.selectOptions(foo, value);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: value })\n      );\n\n      userEvent.deselectOptions(foo, foo0.value);\n      fireEvent.submit(form);\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({ foo: [foo1.value] })\n      );\n\n      userEvent.deselectOptions(foo, foo1.value);\n      fireEvent.submit(form);\n      await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ foo: [] }));\n    });\n\n    it(\"should handle file correctly\", async () => {\n      renderHelper({\n        defaultValues: { foo: null },\n        onSubmit,\n        children: <input data-testid=\"foo\" name=\"foo\" type=\"file\" />,\n      });\n      userEvent.upload(\n        screen.getByTestId(\"foo\"),\n        new File([\"🍎\"], \"🍎.png\", { type: \"image/png\" })\n      );\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({\n          foo: {\n            \"0\": expect.any(Object),\n            item: expect.any(Function),\n            length: 1,\n          },\n        })\n      );\n    });\n\n    it(\"should handle files correctly\", async () => {\n      renderHelper({\n        defaultValues: { foo: null },\n        onSubmit,\n        children: <input data-testid=\"foo\" name=\"foo\" type=\"file\" multiple />,\n      });\n      userEvent.upload(screen.getByTestId(\"foo\"), [\n        new File([\"🍎\"], \"🍎.png\", { type: \"image/png\" }),\n        new File([\"🍋\"], \"🍋.png\", { type: \"image/png\" }),\n      ]);\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() =>\n        expect(onSubmit).toHaveBeenCalledWith({\n          foo: {\n            \"0\": expect.any(Object),\n            \"1\": expect.any(Object),\n            item: expect.any(Function),\n            length: 2,\n          },\n        })\n      );\n    });\n  });\n\n  describe(\"validation\", () => {\n    const value = \"🍎\";\n\n    it.each([\"message\", \"state\"])(\n      \"should run built-in validation with %s mode\",\n      async (mode) => {\n        const { getState } = renderHelper({\n          builtInValidationMode: mode as \"message\" | \"state\",\n          onSubmit,\n          onError,\n          children: <input data-testid=\"foo\" name=\"foo\" required />,\n        });\n        const form = screen.getByTestId(\"form\");\n        const foo = screen.getByTestId(\"foo\");\n\n        const errors = {\n          foo: mode === \"message\" ? builtInError : \"valueMissing\",\n        };\n        fireEvent.submit(form);\n        expect(getState(\"isValidating\")).toBeTruthy();\n        await waitFor(() => expect(onError).toHaveBeenCalledWith(errors));\n        expect(getState(\"isValidating\")).toBeFalsy();\n        expect(getState(\"isValid\")).toBeFalsy();\n\n        onError.mockClear();\n        fireEvent.input(foo, { target: { value } });\n        fireEvent.submit(form);\n        expect(getState(\"isValidating\")).toBeTruthy();\n        await waitFor(() => {\n          expect(onSubmit).toHaveBeenCalledWith({ foo: value });\n          expect(onError).not.toHaveBeenCalled();\n        });\n        expect(getState(\"errors\")).toEqual({});\n        expect(getState(\"isValidating\")).toBeFalsy();\n        expect(getState(\"isValid\")).toBeTruthy();\n      }\n    );\n\n    it(\"should run built-in validation with nested fields\", async () => {\n      const errors = { foo: { a: builtInError, b: builtInError } };\n      renderHelper({\n        onError,\n        children: (\n          <>\n            <input name=\"foo.a\" required />\n            <input name=\"foo.b\" required />\n          </>\n        ),\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onError).toHaveBeenCalledWith(errors));\n    });\n\n    it(\"should disable built-in validation\", async () => {\n      const { getState } = renderHelper({\n        builtInValidationMode: false,\n        onError,\n        children: <input data-testid=\"foo\" name=\"foo\" required />,\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      expect(getState(\"isValidating\")).toBeTruthy();\n      await waitFor(() => expect(onError).not.toHaveBeenCalled());\n      expect(getState(\"isValidating\")).toBeFalsy();\n      expect(getState(\"isValid\")).toBeTruthy();\n    });\n\n    it(\"should run form-level validation\", async () => {\n      const errors = { foo: \"Required\" };\n      const { getState } = renderHelper({\n        validate: async ({ foo }) => (!foo.length ? errors : {}),\n        onSubmit,\n        onError,\n        children: <input data-testid=\"foo\" name=\"foo\" required />,\n      });\n      const form = screen.getByTestId(\"form\");\n      const foo = screen.getByTestId(\"foo\");\n\n      fireEvent.submit(form);\n      expect(getState(\"isValidating\")).toBeTruthy();\n      await waitFor(() => expect(onError).toHaveBeenCalledWith(errors));\n      expect(getState(\"isValidating\")).toBeFalsy();\n      expect(getState(\"isValid\")).toBeFalsy();\n\n      onError.mockClear();\n      fireEvent.input(foo, { target: { value } });\n      fireEvent.submit(form);\n      expect(getState(\"isValidating\")).toBeTruthy();\n      await waitFor(() => {\n        expect(onSubmit).toHaveBeenCalledWith({ foo: value });\n        expect(onError).not.toHaveBeenCalled();\n      });\n      expect(getState(\"errors\")).toEqual({});\n      expect(getState(\"isValidating\")).toBeFalsy();\n      expect(getState(\"isValid\")).toBeTruthy();\n    });\n\n    it.each([\"normal\", \"shortcut\"])(\n      \"should run field-level validation in %s way\",\n      async (type) => {\n        const errors = { foo: \"Required\" };\n        const validate = async (val: string) =>\n          !val.length ? errors.foo : false;\n        const { getState } = renderHelper({\n          onSubmit,\n          onError,\n          children: ({ field }: API) => (\n            <input\n              data-testid=\"foo\"\n              name=\"foo\"\n              ref={field(type === \"normal\" ? { validate } : validate)}\n            />\n          ),\n        });\n        const form = screen.getByTestId(\"form\");\n        const foo = screen.getByTestId(\"foo\");\n\n        fireEvent.submit(form);\n        expect(getState(\"isValidating\")).toBeTruthy();\n        await waitFor(() => expect(onError).toHaveBeenCalledWith(errors));\n        expect(getState(\"isValidating\")).toBeFalsy();\n        expect(getState(\"isValid\")).toBeFalsy();\n\n        onError.mockClear();\n        fireEvent.input(foo, { target: { value } });\n        fireEvent.submit(form);\n        expect(getState(\"isValidating\")).toBeTruthy();\n        await waitFor(() => {\n          expect(onSubmit).toHaveBeenCalledWith({ foo: value });\n          expect(onError).not.toHaveBeenCalled();\n        });\n        expect(getState(\"errors\")).toEqual({});\n        expect(getState(\"isValidating\")).toBeFalsy();\n        expect(getState(\"isValid\")).toBeTruthy();\n      }\n    );\n\n    it(\"should run field-level validation with nested fields\", async () => {\n      const errors = { foo: { a: \"Required\", b: \"Required\" } };\n      renderHelper({\n        onError,\n        children: ({ field }: API) => (\n          <>\n            <input\n              name=\"foo.a\"\n              ref={field((val: string) => (!val.length ? errors.foo.a : false))}\n            />\n            <input\n              name=\"foo.b\"\n              ref={field((val: string) => (!val.length ? errors.foo.b : false))}\n            />\n          </>\n        ),\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onError).toHaveBeenCalledWith(errors));\n    });\n\n    it(\"should run field-level validation with dependent fields\", async () => {\n      const errors = { foo: \"Bar is required\" };\n      renderHelper({\n        onSubmit,\n        onError,\n        children: ({ field }: API) => (\n          <>\n            <input\n              name=\"foo\"\n              ref={field((_, values) =>\n                !values.bar.length ? errors.foo : false\n              )}\n            />\n            <input data-testid=\"bar\" name=\"bar\" />\n          </>\n        ),\n      });\n      const form = screen.getByTestId(\"form\");\n\n      fireEvent.submit(form);\n      await waitFor(() => expect(onError).toHaveBeenCalledWith(errors));\n\n      onError.mockClear();\n      fireEvent.input(screen.getByTestId(\"bar\"), { target: { value } });\n      fireEvent.submit(form);\n      await waitFor(() => {\n        expect(onSubmit).toHaveBeenCalledWith({ foo: \"\", bar: value });\n        expect(onError).not.toHaveBeenCalled();\n      });\n    });\n\n    it.each([\"run\", \"disable\"])(\n      \"should %s validation on change\",\n      async (type) => {\n        const { getState, setValue } = renderHelper({\n          validateOnChange: type === \"run\",\n          children: <input data-testid=\"foo\" name=\"foo\" required />,\n        });\n        const error = type === \"run\" ? { foo: builtInError } : {};\n\n        fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"\" } });\n        await waitFor(() => expect(getState(\"errors\")).toEqual(error));\n\n        setValue(\"foo\", \"\");\n        await waitFor(() => expect(getState(\"errors\")).toEqual(error));\n      }\n    );\n\n    it.each([\"run\", \"disable\"])(\n      \"should %s validation on blur\",\n      async (type) => {\n        const { getState, setTouched } = renderHelper({\n          validateOnChange: false,\n          validateOnBlur: type === \"run\",\n          children: <input data-testid=\"foo\" name=\"foo\" required />,\n        });\n        const error = type === \"run\" ? { foo: builtInError } : {};\n\n        fireEvent.focusOut(screen.getByTestId(\"foo\"));\n        await waitFor(() => expect(getState(\"errors\")).toEqual(error));\n\n        setTouched(\"foo\");\n        await waitFor(() => expect(getState(\"errors\")).toEqual(error));\n      }\n    );\n\n    it(\"should avoid repeatedly validation\", async () => {\n      const validate = jest.fn();\n      renderHelper({\n        validate,\n        children: <input data-testid=\"foo\" name=\"foo\" />,\n      });\n      const foo = screen.getByTestId(\"foo\");\n\n      fireEvent.focusOut(foo);\n      await waitFor(() => expect(validate).toHaveBeenCalled());\n\n      validate.mockClear();\n      fireEvent.input(foo);\n      await waitFor(() => expect(validate).toHaveBeenCalled());\n      fireEvent.focusOut(foo);\n      await waitFor(() => expect(validate).toHaveBeenCalledTimes(1));\n    });\n\n    it(\"should merge form-level error correctly\", async () => {\n      const error = \"Field required\";\n      const { getState } = renderHelper({\n        onSubmit,\n        onError,\n        children: ({ field }: API) => (\n          <input\n            data-testid=\"foo\"\n            name=\"foo\"\n            ref={field(() => error)}\n            required\n          />\n        ),\n      });\n      fireEvent.input(screen.getByTestId(\"foo\"));\n      await waitFor(() => expect(getState(\"errors.foo\")).toBe(error));\n    });\n\n    it(\"should merge field-level error correctly\", async () => {\n      const error = \"Form required\";\n      const { getState } = renderHelper({\n        validate: async () => ({ foo: error }),\n        onSubmit,\n        onError,\n        children: ({ field }: API) => (\n          <input\n            data-testid=\"foo\"\n            name=\"foo\"\n            ref={field(() => \"Field required\")}\n            required\n          />\n        ),\n      });\n      fireEvent.input(screen.getByTestId(\"foo\"));\n      await waitFor(() => expect(getState(\"errors.foo\")).toBe(error));\n    });\n  });\n\n  describe(\"exclude fields\", () => {\n    const defaultValues = { foo: \"🍋\" };\n    const e = { target: { value: \"🍎\" } };\n\n    it(\"should exclude a field via excludeFields option\", async () => {\n      renderHelper({\n        defaultValues,\n        excludeFields: [\"foo\", \"#bar\", \".baz\"],\n        onSubmit,\n        children: (\n          <>\n            <input data-testid=\"foo\" name=\"foo\" />\n            <input data-testid=\"bar\" name=\"bar\" id=\"bar\" />\n            <input data-testid=\"baz\" name=\"baz\" className=\"baz\" />\n          </>\n        ),\n      });\n      const foo = screen.getByTestId(\"foo\") as HTMLInputElement;\n      const bar = screen.getByTestId(\"bar\") as HTMLInputElement;\n      const baz = screen.getByTestId(\"baz\") as HTMLInputElement;\n      expect(foo.value).toBe(\"\");\n      expect(bar.value).toBe(\"\");\n      expect(baz.value).toBe(\"\");\n      fireEvent.input(foo, e);\n      fireEvent.input(bar, e);\n      fireEvent.input(baz, e);\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onSubmit).toHaveBeenCalledWith(defaultValues));\n    });\n\n    it(\"should exclude a field via data attribute\", async () => {\n      renderHelper({\n        defaultValues,\n        onSubmit,\n        children: <input data-testid=\"foo\" name=\"foo\" data-rcf-exclude />,\n      });\n      const foo = screen.getByTestId(\"foo\") as HTMLInputElement;\n      expect(foo.value).toBe(\"\");\n      fireEvent.input(foo, e);\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => expect(onSubmit).toHaveBeenCalledWith(defaultValues));\n    });\n\n    it('should ignore \"field\" method', async () => {\n      const mockDate = \"2050-01-09\";\n      renderHelper({\n        defaultValues: { foo: mockDate },\n        excludeFields: [\"foo\"],\n        onSubmit,\n        children: ({ field }: API) => (\n          <input\n            name=\"foo\"\n            type=\"date\"\n            ref={field({\n              validate: () => \"Required\",\n              valueAsNumber: true,\n            })}\n          />\n        ),\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() => {\n        expect(onSubmit).toHaveBeenCalledWith({ foo: mockDate });\n        expect(onError).not.toHaveBeenCalled();\n      });\n    });\n  });\n\n  describe(\"runValidation\", () => {\n    it(\"should run built-in validation correctly\", async () => {\n      const { runValidation, getState } = renderHelper({\n        children: (\n          <>\n            <input name=\"foo\" required />\n            <input name=\"bar\" required />\n            <input name=\"baz\" required />\n          </>\n        ),\n      });\n\n      runValidation(\"foo\");\n      await waitFor(() =>\n        expect(getState(\"errors\")).toEqual({\n          foo: builtInError,\n        })\n      );\n\n      runValidation([\"foo\", \"bar\"]);\n      await waitFor(() =>\n        expect(getState(\"errors\")).toEqual({\n          foo: builtInError,\n          bar: builtInError,\n        })\n      );\n\n      runValidation();\n      await waitFor(() =>\n        expect(getState(\"errors\")).toEqual({\n          foo: builtInError,\n          bar: builtInError,\n          baz: builtInError,\n        })\n      );\n    });\n\n    it(\"should run field-level validation correctly\", async () => {\n      const error = \"Required\";\n      const validate = async (value: string) =>\n        !value.length ? \"Required\" : false;\n      const { runValidation, getState } = renderHelper({\n        children: ({ field }: API) => (\n          <>\n            <input name=\"foo\" ref={field(validate)} />\n            <input name=\"bar\" ref={field(validate)} />\n            <input name=\"baz\" ref={field(validate)} />\n          </>\n        ),\n      });\n\n      runValidation(\"foo\");\n      await waitFor(() =>\n        expect(getState(\"errors\")).toEqual({\n          foo: error,\n        })\n      );\n\n      runValidation([\"foo\", \"bar\"]);\n      await waitFor(() =>\n        expect(getState(\"errors\")).toEqual({\n          foo: error,\n          bar: error,\n        })\n      );\n\n      runValidation();\n      await waitFor(() =>\n        expect(getState(\"errors\")).toEqual({\n          foo: error,\n          bar: error,\n          baz: error,\n        })\n      );\n    });\n\n    it(\"should run form-level validation correctly\", async () => {\n      const error = \"Required\";\n      const { runValidation, getState } = renderHelper({\n        validate: async ({ foo, bar, baz }) => {\n          const errors: { foo?: string; bar?: string; baz?: string } = {};\n          if (!foo.length) errors.foo = error;\n          if (!bar.length) errors.bar = error;\n          if (!baz.length) errors.baz = error;\n          return errors;\n        },\n        children: (\n          <>\n            <input name=\"foo\" />\n            <input name=\"bar\" />\n            <input name=\"baz\" />\n          </>\n        ),\n      });\n\n      runValidation(\"foo\");\n      await waitFor(() =>\n        expect(getState(\"errors\")).toEqual({\n          foo: error,\n        })\n      );\n\n      runValidation([\"foo\", \"bar\"]);\n      await waitFor(() =>\n        expect(getState(\"errors\")).toEqual({\n          foo: error,\n          bar: error,\n        })\n      );\n\n      runValidation();\n      await waitFor(() =>\n        expect(getState(\"errors\")).toEqual({\n          foo: error,\n          bar: error,\n          baz: error,\n        })\n      );\n    });\n\n    it(\"should return correctly\", async () => {\n      let { runValidation } = renderHelper({\n        children: <input name=\"foo\" />,\n      });\n      let isValid = await runValidation();\n      expect(isValid).toBeTruthy();\n      isValid = await runValidation(\"foo\");\n      expect(isValid).toBeTruthy();\n      isValid = await runValidation([\"foo\"]);\n      expect(isValid).toBeTruthy();\n\n      runValidation = renderHelper({\n        children: <input name=\"foo\" required />,\n      }).runValidation;\n      isValid = await runValidation();\n      expect(isValid).toBeFalsy();\n      isValid = await runValidation(\"foo\");\n      expect(isValid).toBeFalsy();\n      isValid = await runValidation([\"foo\"]);\n      expect(isValid).toBeFalsy();\n    });\n\n    it.each([\"all\", \"some\"])(\n      \"should focus on error when validate %s fields\",\n      async (type) => {\n        const { runValidation } = renderHelper({\n          children: (\n            <>\n              <input data-testid=\"foo\" name=\"foo\" required />\n              <input data-testid=\"bar\" name=\"bar\" required />\n            </>\n          ),\n        });\n        const names = type === \"all\" ? undefined : [\"foo\", \"bar\"];\n        await runValidation(names);\n        expect(screen.getByTestId(\"foo\")).toHaveFocus();\n\n        fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"🍎\" } });\n        await runValidation(names);\n        expect(screen.getByTestId(\"bar\")).toHaveFocus();\n      }\n    );\n\n    it(\"should focus on error when validate single field\", async () => {\n      const foo = renderHelper({\n        children: <input data-testid=\"foo\" name=\"foo\" required />,\n      });\n      await foo.runValidation(\"foo\");\n      expect(screen.getByTestId(\"foo\")).toHaveFocus();\n\n      const bar = renderHelper({\n        children: <input data-testid=\"bar\" name=\"bar\" required />,\n      });\n      fireEvent.input(screen.getByTestId(\"bar\"), { target: { value: \"🍎\" } });\n      await bar.runValidation(\"bar\");\n      expect(screen.getByTestId(\"bar\")).not.toHaveFocus();\n    });\n\n    it.each([, [\"foo\"], \"foo\"])(\"should not focus on error\", async (names) => {\n      const { runValidation } = renderHelper({\n        children: <input data-testid=\"foo\" name=\"foo\" required />,\n      });\n      await runValidation(names, { shouldFocus: false });\n      expect(screen.getByTestId(\"foo\")).not.toHaveFocus();\n    });\n\n    it.each([false, []])(\n      \"should disable focus on error\",\n      async (focusOnError) => {\n        const { runValidation } = renderHelper({\n          focusOnError,\n          children: <input data-testid=\"foo\" name=\"foo\" required />,\n        });\n        await runValidation(\"foo\");\n        expect(screen.getByTestId(\"foo\")).not.toHaveFocus();\n      }\n    );\n\n    it.each([\n      [\"bar\", \"foo\"],\n      // eslint-disable-next-line no-return-assign\n      (names: string[]) => ([names[0], names[1]] = [names[1], names[0]]),\n    ])(\n      \"should focus on error by custom order when validate all fields\",\n      async (focusOnError) => {\n        const { runValidation } = renderHelper({\n          focusOnError,\n          children: (\n            <>\n              <input data-testid=\"foo\" name=\"foo\" required />\n              <input data-testid=\"bar\" name=\"bar\" required />\n            </>\n          ),\n        });\n        await runValidation();\n        expect(screen.getByTestId(\"bar\")).toHaveFocus();\n      }\n    );\n\n    it.each([\n      [\"bar\", \"foo\"],\n      // eslint-disable-next-line no-return-assign\n      (names: string[]) => ([names[0], names[1]] = [names[1], names[0]]),\n    ])(\n      \"should focus on error by custom order when validate some fields\",\n      async (focusOnError) => {\n        const { runValidation } = renderHelper({\n          focusOnError,\n          children: (\n            <>\n              <input data-testid=\"foo\" name=\"foo\" required />\n              <input data-testid=\"bar\" name=\"bar\" required />\n            </>\n          ),\n        });\n        await runValidation([\"foo\", \"bar\"]);\n        expect(screen.getByTestId(\"bar\")).toHaveFocus();\n      }\n    );\n  });\n\n  describe(\"focus\", () => {\n    it(\"should focus correctly\", () => {\n      const { focus } = renderHelper({\n        children: <input data-testid=\"foo\" name=\"foo\" />,\n      });\n      focus(\"foo\");\n      expect(screen.getByTestId(\"foo\")).toHaveFocus();\n    });\n\n    it(\"should focus on the first field correctly\", () => {\n      const { focus } = renderHelper({\n        children: (\n          <>\n            <input data-testid=\"foo.a\" name=\"foo.a\" />\n            <input data-testid=\"foo.b\" name=\"foo.b\" />\n          </>\n        ),\n      });\n      focus(\"foo\");\n      expect(screen.getByTestId(\"foo.a\")).toHaveFocus();\n    });\n\n    it(\"should delay to focus\", () => {\n      jest.useFakeTimers();\n\n      const { focus } = renderHelper({\n        children: <input data-testid=\"foo\" name=\"foo\" />,\n      });\n      const delay = 1000;\n      focus(\"foo\", delay);\n      expect(screen.getByTestId(\"foo\")).not.toHaveFocus();\n      jest.advanceTimersByTime(delay);\n      expect(screen.getByTestId(\"foo\")).toHaveFocus();\n    });\n  });\n\n  describe(\"use\", () => {\n    const { values, isValid } = { ...initialState, values: { foo: \"🍎\" } };\n\n    it('should return undefined if \"path\" isn\\'t set', () => {\n      const { use } = renderHelper();\n      // @ts-expect-error\n      expect(use()).toBeUndefined();\n    });\n\n    it(\"should get default value correctly\", () => {\n      const formValue = { foo: null };\n      const selectValue = { foo: \"🍎\" };\n      let { use } = renderHelper({ defaultValues: formValue });\n      expect(use(\"values.foo\")).toBe(formValue.foo);\n\n      expect(use(\"values.foo\", { defaultValues: selectValue })).toBe(\n        formValue.foo\n      );\n\n      use = renderHelper().use;\n      expect(use(\"values.foo\", { defaultValues: selectValue })).toBe(\n        selectValue.foo\n      );\n\n      expect(use(\"values.foo\")).toBeUndefined();\n    });\n\n    it(\"should get state's values with correct format\", () => {\n      const { use } = renderHelper({ defaultValues: values });\n\n      expect(use(\"values\")).toEqual(values);\n      expect(use(\"values.foo\")).toBe(values.foo);\n      expect(use(\"isValid\")).toBe(isValid);\n\n      expect(use([\"values\", \"values.foo\", \"isValid\"])).toEqual([\n        values,\n        values.foo,\n        isValid,\n      ]);\n\n      expect(\n        use({\n          values: \"values\",\n          foo: \"values.foo\",\n          isValid: \"isValid\",\n        })\n      ).toEqual({ values, foo: values.foo, isValid });\n    });\n\n    it(\"should get form's values by shortcut\", () => {\n      const { use } = renderHelper({ defaultValues: values });\n      const { foo } = values;\n      expect(use(\"foo\")).toBe(foo);\n      expect(use([\"foo\"])).toEqual([foo]);\n      expect(use({ foo: \"foo\" })).toEqual({ foo });\n    });\n\n    it(\"should get error with touched\", async () => {\n      const { use } = renderHelper({\n        children: <input data-testid=\"foo\" name=\"foo\" required />,\n      });\n      const foo = screen.getByTestId(\"foo\");\n\n      fireEvent.input(foo, { target: { value: \"\" } });\n      await waitFor(() => {\n        expect(use(\"errors.foo\")).not.toBeUndefined();\n        expect(use(\"errors.foo\", { errorWithTouched: true })).toBeUndefined();\n      });\n\n      fireEvent.focusOut(foo);\n      await waitFor(() => {\n        expect(\n          use(\"errors.foo\", { errorWithTouched: true })\n        ).not.toBeUndefined();\n      });\n    });\n\n    it(\"should trigger re-rendering correctly\", () => {\n      const { use } = renderHelper({\n        onRender,\n        children: (\n          <>\n            <input data-testid=\"foo\" name=\"foo\" />\n            <input data-testid=\"bar\" name=\"bar\" />\n          </>\n        ),\n      });\n\n      use(\"foo\");\n      fireEvent.input(screen.getByTestId(\"foo\"));\n      expect(onRender).toHaveBeenCalledTimes(2);\n\n      use(\"bar\");\n      fireEvent.input(screen.getByTestId(\"bar\"));\n      expect(onRender).toHaveBeenCalledTimes(3);\n    });\n  });\n\n  describe(\"getState\", () => {\n    const state = { ...initialState, values: { foo: \"🍎\" } };\n    const { values, isValid } = state;\n\n    it(\"should get state\", () => {\n      const { getState } = renderHelper({ defaultValues: values });\n      expect(getState()).toEqual(state);\n    });\n\n    it(\"should get state's values with correct format\", () => {\n      const { getState } = renderHelper({ defaultValues: values });\n\n      expect(getState(\"values\")).toEqual(values);\n      expect(getState(\"foo\")).toBe(values.foo);\n      expect(getState(\"isValid\")).toBe(isValid);\n\n      expect(getState([\"values\", \"values.foo\", \"isValid\"])).toEqual([\n        values,\n        values.foo,\n        isValid,\n      ]);\n\n      expect(\n        getState({\n          values: \"values\",\n          foo: \"values.foo\",\n          isValid: \"isValid\",\n        })\n      ).toEqual({ values, foo: values.foo, isValid });\n    });\n\n    it(\"should get delete value correctly\", () => {\n      const { getState, setValue } = renderHelper({ defaultValues: values });\n      act(() => setValue(\"foo\"));\n      expect(getState(\"foo\")).toBeUndefined();\n    });\n\n    it(\"should get form's values by shortcut\", () => {\n      const { getState } = renderHelper({ defaultValues: values });\n      const { foo } = values;\n      expect(getState(\"foo\")).toBe(foo);\n      expect(getState([\"foo\"])).toEqual([foo]);\n      expect(getState({ foo: \"foo\" })).toEqual({ foo });\n    });\n\n    it(\"should not trigger re-rendering\", () => {\n      const { getState } = renderHelper({\n        onRender,\n        children: <input data-testid=\"foo\" name=\"foo\" />,\n      });\n      getState(\"foo\");\n      fireEvent.input(screen.getByTestId(\"foo\"));\n      expect(onRender).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe(\"setValue\", () => {\n    it(\"should set value correctly\", () => {\n      const { setValue, getState } = renderHelper();\n      const value = \"🍎\";\n\n      setValue(\"foo\", value);\n      expect(getState(\"foo\")).toBe(value);\n\n      setValue(\"foo\", (prevValue: string) => prevValue);\n      expect(getState(\"foo\")).toBe(value);\n\n      setValue(\"foo.a[0].b\", value);\n      expect(getState(\"foo.a[0].b\")).toBe(value);\n\n      setValue(\"foo\");\n      expect(getState(\"foo\")).toBeUndefined();\n    });\n\n    it(\"should set value with touched correctly\", () => {\n      const { setValue, getState } = renderHelper();\n\n      setValue(\"foo\", \"🍎\", { shouldTouched: false });\n      expect(getState(\"touched.foo\")).toBeUndefined();\n\n      setValue(\"foo\", \"🍎\");\n      expect(getState(\"touched.foo\")).toBeTruthy();\n    });\n\n    it(\"should set value with dirty correctly\", () => {\n      const { setValue, getState } = renderHelper();\n\n      setValue(\"foo\", \"🍎\", { shouldDirty: false });\n      expect(getState(\"dirty.foo\")).toBeUndefined();\n      expect(getState(\"isDirty\")).toBeFalsy();\n\n      setValue(\"foo\", \"🍎\");\n      expect(getState(\"dirty.foo\")).toBeTruthy();\n      expect(getState(\"isDirty\")).toBeTruthy();\n    });\n\n    it(\"should set value with validation correctly\", async () => {\n      const { setValue, getState } = renderHelper({\n        children: <input data-testid=\"foo\" name=\"foo\" required />,\n      });\n\n      setValue(\"foo\", \"\", { shouldValidate: false });\n      await waitFor(() => expect(getState(\"errors.foo\")).toBeUndefined());\n\n      setValue(\"foo\", \"\");\n      await waitFor(() => expect(getState(\"errors.foo\")).toBe(builtInError));\n    });\n  });\n\n  describe(\"setTouched\", () => {\n    it(\"should set touched correctly\", () => {\n      const { setTouched, getState } = renderHelper();\n\n      setTouched(\"foo\");\n      expect(getState(\"touched.foo\")).toBeTruthy();\n\n      setTouched(\"foo.a[0].b\");\n      expect(getState(\"touched.foo.a[0].b\")).toBeTruthy();\n\n      setTouched(\"foo\", false);\n      expect(getState(\"touched.foo\")).toBeUndefined();\n    });\n\n    it(\"should set touched with validation correctly\", async () => {\n      const { setTouched, getState } = renderHelper({\n        children: <input data-testid=\"foo\" name=\"foo\" required />,\n      });\n\n      setTouched(\"foo\", true, { shouldValidate: false });\n      await waitFor(() => expect(getState(\"errors.foo\")).toBeUndefined());\n\n      setTouched(\"foo\");\n      await waitFor(() => expect(getState(\"errors.foo\")).toBe(builtInError));\n    });\n  });\n\n  it(\"should set dirty correctly\", () => {\n    const { setDirty, getState } = renderHelper();\n\n    setDirty(\"foo\");\n    expect(getState(\"dirty.foo\")).toBeTruthy();\n\n    setDirty(\"foo.a[0].b\");\n    expect(getState(\"dirty.foo.a[0].b\")).toBeTruthy();\n\n    setDirty(\"foo\", false);\n    expect(getState(\"dirty.foo\")).toBeUndefined();\n  });\n\n  it(\"should set error correctly\", () => {\n    const { setError, getState } = renderHelper();\n    const error = \"Required\";\n\n    setError(\"foo\", error);\n    expect(getState(\"errors.foo\")).toBe(error);\n\n    setError(\"foo\", (prevError: string) => prevError);\n    expect(getState(\"errors.foo\")).toBe(error);\n\n    setError(\"foo.a[0].b\", error);\n    expect(getState(\"errors.foo.a[0].b\")).toBe(error);\n\n    setError(\"foo\");\n    expect(getState(\"errors.foo\")).toBeUndefined();\n\n    setError(\"foo\", error);\n    setError(\"foo\", false);\n    expect(getState(\"errors.foo\")).toBeUndefined();\n\n    setError(\"foo\", error);\n    setError(\"foo\", null);\n    expect(getState(\"errors.foo\")).toBeUndefined();\n\n    setError(\"foo\", error);\n    setError(\"foo\", \"\");\n    expect(getState(\"errors.foo\")).toBeUndefined();\n  });\n\n  it(\"should clear error(s)\", () => {\n    const { setError, clearErrors, getState } = renderHelper();\n    const error = \"Required\";\n\n    setError(\"foo\", error);\n    setError(\"bar\", error);\n    setError(\"baz.a[0].b\", error);\n    expect(getState(\"errors\")).toEqual({\n      foo: error,\n      bar: error,\n      baz: { a: [{ b: error }] },\n    });\n\n    clearErrors(\"foo\");\n    expect(getState(\"errors.foo\")).toBeUndefined();\n\n    clearErrors([\"bar\", \"baz.a[0].b\"]);\n    expect(getState(\"errors.bar\")).toBeUndefined();\n    expect(getState(\"baz.a[0].b\")).toBeUndefined();\n\n    setError(\"foo\", error);\n    clearErrors();\n    expect(getState(\"errors\")).toEqual({});\n  });\n\n  it.each([\"number\", \"date\", \"custom\"])(\n    \"should convert field value to %s\",\n    async (type) => {\n      const value = {\n        number: expect.any(Number),\n        date: expect.any(Date),\n        custom: \"🍎\",\n      };\n      renderHelper({\n        onSubmit,\n        children: ({ field }: API) => (\n          <input\n            data-testid=\"foo\"\n            name=\"foo\"\n            type=\"date\"\n            ref={field({\n              valueAsNumber: type === \"number\",\n              valueAsDate: type === \"date\",\n              parse: type === \"custom\" ? () => value[type] : undefined,\n            })}\n          />\n        ),\n      });\n      fireEvent.input(screen.getByTestId(\"foo\"), {\n        target: { value: \"1970-01-01\" },\n      });\n      fireEvent.submit(screen.getByTestId(\"form\"));\n      await waitFor(() =>\n        // @ts-expect-error\n        expect(onSubmit).toHaveBeenCalledWith({ foo: value[type] })\n      );\n    }\n  );\n\n  it.each([\"normal\", \"exclude\"])(\"should remove field correctly\", (type) => {\n    const value = \"🍎\";\n    const { setError, setTouched, setDirty, removeField, reset, getState } =\n      renderHelper({\n        children: <input data-testid=\"foo\" name=\"foo\" defaultValue=\"🍎\" />,\n      });\n\n    act(() => {\n      setError(\"foo\", \"Required\");\n      setTouched(\"foo\", true, { shouldValidate: false });\n      setDirty(\"foo\");\n      removeField(\n        \"foo\",\n        type === \"normal\"\n          ? undefined\n          : [\"defaultValue\", \"value\", \"error\", \"touched\", \"dirty\"]\n      );\n    });\n    expect(getState()).toEqual(\n      type === \"normal\"\n        ? initialState\n        : {\n            ...initialState,\n            values: { foo: value },\n            errors: { foo: \"Required\" },\n            isValid: false,\n            touched: { foo: true },\n            dirty: { foo: true },\n            isDirty: true,\n          }\n    );\n\n    act(() => reset());\n    expect(getState(\"foo\")).toEqual(type === \"normal\" ? undefined : value);\n\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"🍋\" } });\n    expect(getState(\"foo\")).toBe(type === \"normal\" ? undefined : value);\n  });\n\n  it('should trigger \"onStateChange\" correctly', async () => {\n    const onStateChange = jest.fn();\n    renderHelper({\n      onStateChange,\n      children: <input data-testid=\"foo\" name=\"foo\" />,\n    });\n    const value = \"🍎\";\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value } });\n    await waitFor(() => {\n      expect(onStateChange).toHaveBeenCalledTimes(3);\n      expect(onStateChange).toHaveBeenNthCalledWith(1, {\n        ...initialState,\n        values: { foo: \"\" },\n      });\n      expect(onStateChange).toHaveBeenNthCalledWith(2, {\n        ...initialState,\n        values: { foo: value },\n      });\n      expect(onStateChange).toHaveBeenNthCalledWith(3, {\n        ...initialState,\n        values: { foo: value },\n        dirty: { foo: true },\n        isDirty: true,\n      });\n    });\n  });\n\n  describe(\"conditional fields\", () => {\n    it.each([\"form\", \"field\"])(\n      \"should set %s-level default value for single field correctly\",\n      async (type) => {\n        const formValue = \"🍎\";\n        const fieldValue = \"🍋\";\n        const { getState, setError, setTouched, setDirty, setShow } =\n          renderHelper({\n            defaultValues: type === \"form\" ? { foo: formValue } : undefined,\n            children: ({ show }: API) => (\n              <>\n                {show && (\n                  <input\n                    data-testid=\"foo\"\n                    name=\"foo\"\n                    defaultValue={type === \"field\" ? fieldValue : undefined}\n                  />\n                )}\n              </>\n            ),\n          });\n\n        act(() => setShow(true));\n        await waitFor(() => {\n          expect(getState(\"foo\")).toBe(\n            type === \"form\" ? formValue : fieldValue\n          );\n          expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(\n            type === \"form\" ? formValue : fieldValue\n          );\n        });\n\n        act(() => {\n          setError(\"foo\", \"Required\");\n          setTouched(\"foo\", true, { shouldValidate: false });\n          setDirty(\"foo\");\n          setShow(false);\n        });\n        await waitFor(() => expect(getState()).toEqual(initialState));\n\n        act(() => setShow(true));\n        await waitFor(() => {\n          expect(getState()).toEqual({\n            ...initialState,\n            values: { foo: type === \"field\" ? fieldValue : undefined },\n          });\n          expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(\n            type === \"field\" ? fieldValue : \"\"\n          );\n        });\n      }\n    );\n\n    it.each([\"form\", \"field\"])(\n      \"should set %s-level default value for multiple fields correctly\",\n      async (type) => {\n        const value = [\"🍎\", \"🍋\"];\n        const { getState, setError, setTouched, setDirty, setShow } =\n          renderHelper({\n            defaultValues: type === \"form\" ? { foo: value } : undefined,\n            children: ({ show }: API) => (\n              <>\n                <input\n                  data-testid=\"foo-0\"\n                  name=\"foo\"\n                  type=\"checkbox\"\n                  value={value[0]}\n                  defaultChecked={type === \"field\"}\n                />\n                {show && (\n                  <input\n                    data-testid=\"foo-1\"\n                    name=\"foo\"\n                    type=\"checkbox\"\n                    value={value[1]}\n                    defaultChecked={type === \"field\"}\n                  />\n                )}\n              </>\n            ),\n          });\n\n        act(() => setShow(true));\n        await waitFor(() => {\n          expect(getState(\"foo\")).toEqual(type === \"form\" ? value : [value[0]]);\n          expect(screen.getByTestId(\"foo-0\")).toBeChecked();\n          expect(screen.getByTestId(\"foo-1\")).toBeChecked();\n        });\n\n        act(() => {\n          setError(\"foo\", \"Required\");\n          setTouched(\"foo\", true, { shouldValidate: false });\n          setDirty(\"foo\");\n          setShow(false);\n        });\n        const state = {\n          ...initialState,\n          values: { foo: [value[0]] },\n          errors: { foo: \"Required\" },\n          isValid: false,\n          touched: { foo: true },\n          dirty: { foo: true },\n          isDirty: true,\n        };\n        await waitFor(() => expect(getState()).toEqual(state));\n\n        act(() => setShow(true));\n        await waitFor(() => {\n          expect(getState()).toEqual(state);\n          expect(screen.getByTestId(\"foo-0\")).toBeChecked();\n          expect(screen.getByTestId(\"foo-1\")).toBeChecked();\n        });\n      }\n    );\n\n    it(\"should remove array fields correctly\", async () => {\n      const { getState, setShow } = renderHelper({\n        defaultValues: { foo: [\"🍎\", \"🍋\"] },\n        isShow: true,\n        children: ({ show }: API) => (\n          <>\n            {show && <input name=\"foo[0]\" />}\n            {show && <input name=\"foo[1]\" />}\n          </>\n        ),\n      });\n      act(() => setShow(false));\n      await waitFor(() => expect(getState(\"values\")).toEqual({}));\n    });\n\n    it.each([false, [], () => []])(\n      \"should not remove field\",\n      async (removeOnUnmounted) => {\n        const value = \"🍎\";\n        const { getState, setError, setTouched, setDirty, setShow } =\n          renderHelper({\n            isShow: true,\n            removeOnUnmounted,\n            children: ({ show }: API) => (\n              <>\n                {show && (\n                  <input data-testid=\"foo\" name=\"foo\" defaultValue={value} />\n                )}\n              </>\n            ),\n          });\n\n        act(() => {\n          setError(\"foo\", \"Required\");\n          setTouched(\"foo\", true, { shouldValidate: false });\n          setDirty(\"foo\");\n          setShow(false);\n        });\n        await Promise.resolve();\n        expect(getState()).toEqual({\n          ...initialState,\n          values: { foo: value },\n          errors: { foo: \"Required\" },\n          isValid: false,\n          touched: { foo: true },\n          dirty: { foo: true },\n          isDirty: true,\n        });\n\n        act(() => setShow(true));\n        await waitFor(() =>\n          expect((screen.getByTestId(\"foo\") as HTMLInputElement).value).toBe(\n            value\n          )\n        );\n      }\n    );\n\n    it(\"should trigger re-rendering correctly\", async () => {\n      const { setValue, setError, setTouched, setDirty, setShow, use } =\n        renderHelper({\n          isShow: true,\n          onRender,\n          children: ({ show }: API) => <>{show && <input name=\"foo\" />}</>,\n        });\n      use([\"foo\", \"errors.foo\", \"touched.foo\", \"dirty.foo\"]);\n      act(() => {\n        setValue(\"foo\", \"🍎\", { shouldValidate: false });\n        setError(\"foo\", \"Required\");\n        setTouched(\"foo\", true, { shouldValidate: false });\n        setDirty(\"foo\");\n      });\n      act(() => setShow(false));\n      await waitFor(() => expect(onRender).toHaveBeenCalledTimes(4));\n    });\n  });\n});\n"
  },
  {
    "path": "src/useForm.ts",
    "content": "/* eslint-disable @typescript-eslint/no-use-before-define */\n\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { dequal } from \"dequal/lite\";\n\nimport * as shared from \"./shared\";\nimport {\n  ClearErrors,\n  FieldArray,\n  FieldElement,\n  Fields,\n  FieldValidator,\n  Focus,\n  FormConfig,\n  FormErrors,\n  FormMethods,\n  FormState,\n  FormValues,\n  GetFormState,\n  GetNodeValue,\n  GetState,\n  HandleChangeEvent,\n  Handlers,\n  ObjMap,\n  Parsers,\n  RegisterField,\n  RegisterForm,\n  RemoveField,\n  Reset,\n  RunValidation,\n  SetDefaultValue,\n  SetDirty,\n  SetError,\n  SetNodesOrValues,\n  SetTouched,\n  SetTouchedMaybeValidate,\n  SetValue,\n  ShouldRemoveField,\n  Submit,\n  Use,\n} from \"./types\";\nimport { useLatest, useState } from \"./hooks\";\nimport {\n  arrayToMap,\n  compact,\n  deepMerge,\n  filterErrors,\n  get,\n  getPath,\n  isAsyncFunction,\n  isCheckboxInput,\n  isEmptyObject,\n  isFieldArray,\n  isFieldElement,\n  isFileInput,\n  isFileList,\n  isFunction,\n  isInputElement,\n  isNumberInput,\n  isPlainObject,\n  isRadioInput,\n  isRangeInput,\n  isSelectMultiple,\n  isSelectOne,\n  isUndefined,\n  parseState,\n  runWithLowPriority,\n  set,\n  unset,\n  warn,\n} from \"./utils\";\n\nexport default <V extends FormValues = FormValues>({\n  id,\n  defaultValues = {} as V,\n  validate,\n  validateOnChange = true,\n  validateOnBlur = true,\n  focusOnError = true,\n  removeOnUnmounted = true,\n  builtInValidationMode = \"message\",\n  excludeFields = [],\n  onReset,\n  onSubmit,\n  onError,\n  onStateChange,\n}: FormConfig<V> = {}): FormMethods<V> => {\n  const handlersRef = useRef<Handlers>({});\n  const mutationObserverRef = useRef<MutationObserver>();\n  const formRef = useRef<HTMLElement>();\n  const fieldsRef = useRef<Fields>(new Map());\n  const fieldParsersRef = useRef<Parsers>({});\n  const fieldArrayRef = useRef<FieldArray>({});\n  const controlsRef = useRef<ObjMap>({});\n  const formValidatorRef = useLatest(validate);\n  const fieldValidatorsRef = useRef<ObjMap<FieldValidator<V>>>({});\n  const changedFieldRef = useRef<string>();\n  const excludeFieldsRef = useRef<ObjMap>(arrayToMap(excludeFields));\n  const onResetRef = useLatest(onReset || (() => undefined));\n  const onSubmitRef = useLatest(onSubmit || (() => undefined));\n  const onErrorRef = useLatest(onError || (() => undefined));\n  const hasWarnValues = useRef(false);\n  const initialStateRef = useRef<FormState<V>>({\n    values: defaultValues,\n    touched: {},\n    errors: {},\n    isDirty: false,\n    dirty: {},\n    isValidating: false,\n    isValid: true,\n    isSubmitting: false,\n    isSubmitted: false,\n    submitCount: 0,\n  });\n  const { stateRef, setStateRef, observersRef } = useState<V>(\n    { ...initialStateRef.current },\n    onStateChange\n  );\n\n  const handleUnset = useCallback(\n    (\n      path: string,\n      options?: { shouldSkipUpdate?: boolean; shouldForceUpdate?: boolean }\n    ) => {\n      const segs = path.split(\".\");\n      const k = segs.shift() as string;\n      setStateRef(\n        k,\n        unset(stateRef.current[k as keyof FormState<V>], segs.join(\".\"), true),\n        { fieldPath: path, ...options }\n      );\n    },\n    [setStateRef, stateRef]\n  );\n\n  const handleFocus = useCallback((name: string) => {\n    const field =\n      fieldsRef.current.get(name)?.field ||\n      fieldsRef.current.get(\n        Array.from(fieldsRef.current.keys()).find((n) => n.startsWith(name)) ||\n          \"\"\n      )?.field;\n\n    if (field && isFunction(field.focus)) field.focus();\n  }, []);\n\n  const getFields = useCallback(\n    (form: HTMLElement) =>\n      Array.from(form.querySelectorAll(\"input,textarea,select\"))\n        .filter((element) => {\n          const field = element as FieldElement;\n          const {\n            type,\n            name,\n            id: fieldId,\n            classList,\n            dataset: { rcfExclude },\n          } = field;\n          const { current: exclude } = excludeFieldsRef;\n\n          if (\n            /button|image|submit|reset/.test(type) ||\n            (fieldId && exclude[`#${fieldId}`]) ||\n            Array.from(classList).find((n) => exclude[`.${n}`])\n          )\n            return false;\n\n          if (rcfExclude !== \"true\" && !name) {\n            warn(\n              '💡 react-cool-form > field: Missing \"name\" attribute. Do you want to exclude the field? See: https://react-cool-form.netlify.app/docs/api-reference/use-form/#excludefields'\n            );\n            return false;\n          }\n\n          return (\n            controlsRef.current[name] ||\n            (rcfExclude !== \"true\" && !exclude[name])\n          );\n        })\n        .reduce((acc, elm) => {\n          const field = elm as FieldElement;\n          const { name } = field;\n          const fieldArrayName = isFieldArray(fieldArrayRef.current, name);\n\n          if (fieldArrayName)\n            fieldArrayRef.current[fieldArrayName].fields[name] = true;\n\n          acc.set(name, {\n            ...acc.get(name),\n            field: acc.get(name)?.field || field,\n          });\n\n          if (isCheckboxInput(field) || isRadioInput(field)) {\n            acc.get(name).options = acc.get(name).options\n              ? [...acc.get(name).options, field]\n              : [field];\n          } else if (isSelectOne(field) || isSelectMultiple(field)) {\n            acc.get(name).options = Array.from(field.options);\n          }\n\n          return acc;\n        }, new Map()),\n    []\n  );\n\n  const getNodeValue = useCallback<GetNodeValue>(\n    (name, fields = fieldsRef.current) => {\n      if (!fields.has(name)) return undefined;\n\n      const { field, options } = fields.get(name)!;\n\n      if (isInputElement(field)) {\n        if (fieldParsersRef.current[name]?.valueAsNumber)\n          return field.valueAsNumber;\n        if (fieldParsersRef.current[name]?.valueAsDate)\n          return field.valueAsDate;\n      }\n\n      if (isNumberInput(field) || isRangeInput(field))\n        return field.valueAsNumber || \"\";\n\n      if (isCheckboxInput(field)) {\n        const checkboxes = options as HTMLInputElement[];\n\n        if (checkboxes.length > 1)\n          return checkboxes.filter((c) => c.checked).map((c) => c.value);\n\n        const checkbox = checkboxes[0];\n\n        if (checkbox.hasAttribute(\"value\") && checkbox.value)\n          return checkbox.checked ? [checkbox.value] : [];\n\n        return checkbox.checked;\n      }\n\n      if (isRadioInput(field))\n        return (\n          (options as HTMLInputElement[]).find((radio) => radio.checked)\n            ?.value || \"\"\n        );\n\n      if (isSelectMultiple(field))\n        return (options as HTMLOptionElement[])\n          .filter((option) => option.selected)\n          .map((option) => option.value);\n\n      if (isFileInput(field)) return field.files;\n\n      return field.value;\n    },\n    []\n  );\n\n  const setNodeValue = useCallback(\n    (name: string, value: any, fields: Fields = fieldsRef.current) => {\n      if (!fields.has(name) || controlsRef.current[name]) return;\n\n      const { field, options } = fields.get(name)!;\n\n      if (isCheckboxInput(field)) {\n        const checkboxes = options as HTMLInputElement[];\n\n        if (checkboxes.length > 1) {\n          checkboxes.forEach((checkbox) => {\n            checkbox.checked = Array.isArray(value)\n              ? value.includes(checkbox.value)\n              : !!value;\n          });\n        } else {\n          checkboxes[0].checked = !!value;\n        }\n      } else if (isRadioInput(field)) {\n        (options as HTMLInputElement[]).forEach((radio) => {\n          radio.checked = radio.value === value;\n        });\n      } else if (isSelectMultiple(field) && Array.isArray(value)) {\n        (options as HTMLOptionElement[]).forEach((option) => {\n          option.selected = !!value.includes(option.value);\n        });\n      } else if (isFileInput(field)) {\n        if (isFileList(value)) field.files = value;\n        if (!value) field.value = \"\";\n      } else {\n        field.value = value ?? \"\";\n      }\n    },\n    []\n  );\n\n  const setDefaultValue = useCallback<SetDefaultValue>(\n    (\n      name,\n      value,\n      shouldUpdateDefaultValue = !isFieldArray(fieldArrayRef.current, name) ||\n        !isUndefined(get(initialStateRef.current.values, name.split(\".\")[0]))\n    ) => {\n      if (shouldUpdateDefaultValue)\n        initialStateRef.current.values = set(\n          initialStateRef.current.values,\n          name,\n          value,\n          true\n        );\n\n      if (!dequal(get(stateRef.current.values, name), value))\n        setStateRef(`values.${name}`, value, { shouldSkipUpdate: true });\n    },\n    [setStateRef, stateRef]\n  );\n\n  const setNodesOrValues = useCallback<SetNodesOrValues<V>>(\n    (\n      values,\n      {\n        shouldSetValues = true,\n        fields = Array.from(fieldsRef.current.keys()),\n      } = {}\n    ) =>\n      fields.forEach((name) => {\n        if (controlsRef.current[name]) return;\n\n        const value = get(values, name);\n\n        if (!isUndefined(value)) setNodeValue(name, value);\n\n        if (shouldSetValues)\n          setDefaultValue(\n            name,\n            !isUndefined(value) ? value : getNodeValue(name)\n          );\n      }),\n    [getNodeValue, setDefaultValue, setNodeValue]\n  );\n\n  const setError = useCallback<SetError>(\n    (name, error) => {\n      error = isFunction(error)\n        ? error(get(stateRef.current.errors, name))\n        : error;\n\n      if (error) {\n        setStateRef(`errors.${name}`, error);\n      } else {\n        handleUnset(`errors.${name}`);\n      }\n    },\n    [handleUnset, setStateRef, stateRef]\n  );\n\n  const clearErrors = useCallback<ClearErrors>(\n    (name) => {\n      if (!name) {\n        setStateRef(\"errors\", {});\n      } else if (Array.isArray(name)) {\n        name.forEach((n) => setError(n));\n      } else {\n        setError(name);\n      }\n    },\n    [setError, setStateRef]\n  );\n\n  const runBuiltInValidation = useCallback(\n    (name: string) => {\n      if (builtInValidationMode === false || !fieldsRef.current.has(name))\n        return undefined;\n\n      const {\n        field: { validity, validationMessage },\n      } = fieldsRef.current.get(name)!;\n\n      if (builtInValidationMode === \"state\")\n        for (const k in validity)\n          if (k !== \"valid\" && validity[k as keyof ValidityState]) return k;\n\n      return validationMessage;\n    },\n    [builtInValidationMode]\n  );\n\n  const runAllBuiltInValidation = useCallback(() => {\n    if (builtInValidationMode === false) return {};\n\n    return Array.from(fieldsRef.current.keys()).reduce((errors, name) => {\n      const error = runBuiltInValidation(name);\n      errors = { ...errors, ...(error ? set(errors, name, error) : {}) };\n      return errors;\n    }, {});\n  }, [builtInValidationMode, runBuiltInValidation]);\n\n  const runFieldValidation = useCallback(\n    async (name: string) => {\n      const value = get(stateRef.current.values, name);\n\n      if (!fieldValidatorsRef.current[name] || isUndefined(value))\n        return undefined;\n\n      try {\n        const error = await fieldValidatorsRef.current[name](\n          value,\n          stateRef.current.values\n        );\n\n        return error;\n      } catch (exception) {\n        warn(`💡 react-cool-form > validate ${name}: `, exception);\n        throw exception;\n      }\n    },\n    [stateRef]\n  );\n\n  const runAllFieldsValidation = useCallback((): Promise<FormErrors<V>> => {\n    const promises = Object.keys(fieldValidatorsRef.current).map((name) =>\n      runFieldValidation(name)\n    );\n\n    return Promise.all(promises).then((errors) =>\n      Object.keys(fieldValidatorsRef.current).reduce((acc, cur, idx) => {\n        acc = { ...acc, ...(errors[idx] ? set(acc, cur, errors[idx]) : {}) };\n        return acc;\n      }, {})\n    );\n  }, [runFieldValidation]);\n\n  const runFormValidation = useCallback(\n    async (name?: string): Promise<any> => {\n      if (!formValidatorRef.current) return name ? undefined : {};\n\n      try {\n        const errors = await formValidatorRef.current(stateRef.current.values);\n\n        if (name) return get(errors, name);\n\n        return isPlainObject(errors) ? errors : {};\n      } catch (exception) {\n        warn(`💡 react-cool-form > validate form: `, exception);\n        throw exception;\n      }\n    },\n    [formValidatorRef, stateRef]\n  );\n\n  const validateField = useCallback(\n    async (name: string) => {\n      const hasAsyncValidator =\n        isAsyncFunction(formValidatorRef.current) ||\n        isAsyncFunction(fieldValidatorsRef.current[name]);\n\n      if (hasAsyncValidator) setStateRef(\"isValidating\", true);\n\n      try {\n        const error =\n          (await runFormValidation(name)) ||\n          (await runFieldValidation(name)) ||\n          runBuiltInValidation(name);\n\n        setError(name, error);\n        if (hasAsyncValidator) setStateRef(\"isValidating\", false);\n\n        return error;\n      } catch (exception) {\n        return exception;\n      }\n    },\n    [\n      formValidatorRef,\n      runBuiltInValidation,\n      runFieldValidation,\n      runFormValidation,\n      setError,\n      setStateRef,\n    ]\n  );\n\n  const validateFieldWithLowPriority = useCallback<typeof validateField>(\n    (name) => runWithLowPriority(() => validateField(name)),\n    [validateField]\n  );\n\n  const validateForm = useCallback((): Promise<FormErrors<V>> => {\n    setStateRef(\"isValidating\", true);\n\n    return Promise.all([\n      runAllBuiltInValidation(),\n      runAllFieldsValidation(),\n      runFormValidation(),\n    ]).then((errors) => {\n      const errs = deepMerge(...errors);\n\n      setStateRef(\"errors\", errs);\n      setStateRef(\"isValidating\", false);\n\n      return errs;\n    });\n  }, [\n    runAllBuiltInValidation,\n    runAllFieldsValidation,\n    runFormValidation,\n    setStateRef,\n  ]);\n\n  const runValidation = useCallback<RunValidation>(\n    (name, { shouldFocus = focusOnError } = {}) => {\n      let names: string[] = [];\n\n      if (shouldFocus) {\n        names = Array.isArray(shouldFocus)\n          ? shouldFocus\n          : Array.from(fieldsRef.current.keys());\n        names = isFunction(shouldFocus) ? shouldFocus(names) : names;\n      }\n\n      if (!name)\n        return validateForm().then((errors) => {\n          if (shouldFocus) {\n            const fieldName = names.find((n) => get(errors, n));\n            if (fieldName) handleFocus(fieldName);\n          }\n\n          return isEmptyObject(errors);\n        });\n\n      if (Array.isArray(name))\n        return Promise.all(name.map((n) => validateField(n))).then((errors) => {\n          if (shouldFocus) {\n            const fieldName = names.find((n) => !!errors[name.indexOf(n)]);\n            if (fieldName) handleFocus(fieldName);\n          }\n\n          return !compact(errors).length;\n        });\n\n      return validateField(name).then((error) => {\n        if (shouldFocus && error && names.includes(name)) handleFocus(name);\n\n        return !error;\n      });\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [handleFocus, validateField, validateForm]\n  );\n\n  const getFormState = useCallback<GetFormState<V>>(\n    (\n      path,\n      {\n        errorWithTouched,\n        defaultValues: dfValues = {},\n        methodName = \"getState\",\n        callback,\n      } = {}\n    ) => {\n      const usedState: ObjMap = {};\n      const state = parseState(\n        path,\n        stateRef.current,\n        (p) => {\n          p = getPath(p);\n\n          if (methodName !== \"getState\") {\n            if (\n              p === \"values\" &&\n              methodName !== \"useFormStateCallback\" &&\n              !hasWarnValues.current\n            ) {\n              warn(\n                `💡 react-cool-form > ${methodName}: Getting \"values\" alone might cause unnecessary re-renders. If you know what you're doing, just ignore this warning. See: https://react-cool-form.netlify.app/docs/getting-started/form-state#best-practices`\n              );\n              hasWarnValues.current = true;\n            }\n\n            usedState[p] = true;\n          }\n\n          return p;\n        },\n        (p, v) => {\n          if (methodName === \"getState\") return v;\n\n          if (p.startsWith(\"values\")) {\n            if (!isUndefined(v)) return v;\n\n            p = p.replace(\"values.\", \"\");\n            v = get(initialStateRef.current, p);\n\n            return !isUndefined(v) ? v : get(dfValues, p);\n          }\n\n          if (!errorWithTouched || !p.startsWith(\"errors\")) return v;\n\n          p = p.replace(\"errors\", \"touched\");\n          usedState[p] = true;\n\n          return filterErrors(v, get(stateRef.current, p));\n        },\n        methodName === \"getState\"\n      );\n\n      if (callback) callback(usedState);\n\n      return state;\n    },\n    [stateRef]\n  );\n\n  const focus = useCallback<Focus>(\n    (name, delay) => {\n      if (!isUndefined(delay)) {\n        setTimeout(() => handleFocus(name), delay);\n      } else {\n        handleFocus(name);\n      }\n    },\n    [handleFocus]\n  );\n\n  const use = useCallback<Use<V>>(\n    (path, { errorWithTouched, defaultValues: dfValues } = {}) =>\n      getFormState(path, {\n        errorWithTouched,\n        defaultValues: dfValues,\n        methodName: \"use\",\n        callback: (usedState) => {\n          observersRef.current[0].usedState = {\n            ...observersRef.current[0].usedState,\n            ...usedState,\n          };\n        },\n      }),\n    [getFormState, observersRef]\n  );\n\n  const getState = useCallback<GetState>(\n    (path) => getFormState(path),\n    [getFormState]\n  );\n\n  const setTouched = useCallback<SetTouched>(\n    (name, isTouched = true, { shouldValidate = validateOnBlur } = {}) => {\n      if (isTouched) {\n        setStateRef(`touched.${name}`, true);\n      } else {\n        handleUnset(`touched.${name}`);\n      }\n\n      if (shouldValidate) validateFieldWithLowPriority(name);\n    },\n    [handleUnset, setStateRef, validateFieldWithLowPriority, validateOnBlur]\n  );\n\n  const setTouchedMaybeValidate = useCallback<SetTouchedMaybeValidate>(\n    (name) =>\n      setTouched(name, true, {\n        shouldValidate: validateOnChange\n          ? name !== changedFieldRef.current\n          : undefined,\n      }),\n    [setTouched, validateOnChange]\n  );\n\n  const setDirty = useCallback<SetDirty>(\n    (name, isDirty = true) => {\n      if (isDirty) {\n        setStateRef(`dirty.${name}`, true);\n      } else {\n        handleUnset(`dirty.${name}`);\n      }\n    },\n    [handleUnset, setStateRef]\n  );\n\n  const setDirtyIfNeeded = useCallback(\n    (name: string) =>\n      setDirty(\n        name,\n        !dequal(\n          get(stateRef.current.values, name),\n          get(initialStateRef.current.values, name)\n        )\n      ),\n    [setDirty, stateRef]\n  );\n\n  const setValue = useCallback<SetValue>(\n    (\n      name,\n      value,\n      {\n        shouldValidate = validateOnChange,\n        shouldTouched = true,\n        shouldDirty = true,\n      } = {}\n    ) => {\n      value = isFunction(value)\n        ? value(get(stateRef.current.values, name))\n        : value;\n\n      if (!isUndefined(value)) {\n        setStateRef(`values.${name}`, value);\n      } else {\n        handleUnset(`values.${name}`);\n      }\n      setNodeValue(name, value);\n\n      isFieldArray(fieldArrayRef.current, name, (key) =>\n        fieldArrayRef.current[key].reset()\n      );\n\n      if (shouldTouched) setTouched(name, true, { shouldValidate: false });\n      if (shouldDirty) setDirtyIfNeeded(name);\n      if (shouldValidate) validateFieldWithLowPriority(name);\n    },\n    [\n      handleUnset,\n      setDirtyIfNeeded,\n      setNodeValue,\n      setStateRef,\n      setTouched,\n      stateRef,\n      validateFieldWithLowPriority,\n      validateOnChange,\n    ]\n  );\n\n  const getOptions = useCallback(\n    () => ({\n      getState,\n      setValue,\n      setTouched,\n      setDirty,\n      setError,\n      clearErrors,\n      runValidation,\n      removeField,\n      focus,\n      reset,\n      submit,\n    }),\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    []\n  );\n\n  const reset: Reset<V> = useCallback(\n    (values, exclude, e) => {\n      if (e?.preventDefault) e.preventDefault();\n      if (e?.stopPropagation) e.stopPropagation();\n\n      const state = { ...stateRef.current };\n      const skip = arrayToMap(exclude || []);\n\n      Object.keys(state).forEach((key) => {\n        if (skip[key]) return;\n\n        if (key === \"values\") {\n          const nextValues =\n            (isFunction(values) ? values(stateRef.current.values) : values) ||\n            initialStateRef.current.values;\n\n          state[key] = nextValues;\n          initialStateRef.current.values = nextValues;\n          setNodesOrValues(nextValues, {\n            shouldSetValues: false,\n            fields: Array.from(fieldsRef.current.keys()).filter(\n              (name) => !isFieldArray(fieldArrayRef.current, name)\n            ),\n          });\n        } else {\n          // @ts-expect-error\n          state[key] = initialStateRef.current[key];\n        }\n      });\n\n      setStateRef(\"\", state);\n      onResetRef.current(state.values, getOptions(), e);\n\n      Object.values(fieldArrayRef.current).forEach((field) => field.reset());\n    },\n    [getOptions, onResetRef, setNodesOrValues, setStateRef, stateRef]\n  );\n\n  const submit: Submit<V> = useCallback(\n    async (e) => {\n      if (e?.preventDefault) e.preventDefault();\n      if (e?.stopPropagation) e.stopPropagation();\n\n      const nextTouched = [\n        ...Array.from(fieldsRef.current.keys()),\n        ...Object.keys(controlsRef.current),\n      ].reduce((touched, name) => {\n        touched = set(touched, name, true, true);\n        return touched;\n      }, stateRef.current.touched);\n\n      setStateRef(\"touched\", nextTouched);\n      setStateRef(\"isSubmitted\", false);\n      setStateRef(\"isSubmitting\", true);\n\n      try {\n        const isValid = await runValidation();\n\n        if (!isValid) {\n          const { errors } = stateRef.current;\n          onErrorRef.current(errors, getOptions(), e);\n          return { errors };\n        }\n\n        await onSubmitRef.current(stateRef.current.values, getOptions(), e);\n        setStateRef(\"isSubmitted\", true);\n\n        return { values: stateRef.current.values };\n      } catch (exception) {\n        warn(`💡 react-cool-form > submit: `, exception);\n        throw exception;\n      } finally {\n        setStateRef(\"isSubmitting\", false);\n      }\n    },\n    [getOptions, onErrorRef, onSubmitRef, runValidation, setStateRef, stateRef]\n  );\n\n  const handleChangeEvent = useCallback<HandleChangeEvent>(\n    (name, value) => {\n      setStateRef(`values.${name}`, value);\n      setDirtyIfNeeded(name);\n\n      if (validateOnChange) validateFieldWithLowPriority(name);\n    },\n    [\n      setDirtyIfNeeded,\n      setStateRef,\n      validateFieldWithLowPriority,\n      validateOnChange,\n    ]\n  );\n\n  const shouldRemoveField = useCallback<ShouldRemoveField>(\n    (name) => {\n      if (!removeOnUnmounted) return false;\n\n      let names = Array.isArray(removeOnUnmounted)\n        ? removeOnUnmounted\n        : [\n            ...Array.from(fieldsRef.current.keys()),\n            ...Object.keys(controlsRef.current),\n            ...Object.keys(fieldArrayRef.current),\n          ];\n      names = isFunction(removeOnUnmounted) ? removeOnUnmounted(names) : names;\n\n      return names.includes(name);\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    []\n  );\n\n  const removeField = useCallback<RemoveField>(\n    (name, exclude) => {\n      const { defaultValue, ...rest } = arrayToMap(exclude || [], {\n        value: \"values\",\n        error: \"errors\",\n      });\n\n      if (!defaultValue)\n        initialStateRef.current.values = unset(\n          initialStateRef.current.values,\n          name,\n          true\n        );\n\n      [\"values\", \"touched\", \"dirty\", \"errors\"].forEach((key, idx, arr) => {\n        const shouldForceUpdate = idx === arr.length - 1;\n\n        if (\n          !rest[key] &&\n          !isUndefined(get(stateRef.current[key as keyof FormState<V>], name))\n        )\n          handleUnset(`${key}.${name}`, {\n            shouldSkipUpdate: !shouldForceUpdate,\n            shouldForceUpdate,\n          });\n      });\n\n      delete fieldParsersRef.current[name];\n      delete fieldValidatorsRef.current[name];\n      delete fieldArrayRef.current[name];\n      delete controlsRef.current[name];\n\n      if (fieldsRef.current.has(name)) fieldsRef.current.delete(name);\n    },\n    [handleUnset, stateRef]\n  );\n\n  const registerForm = useCallback<RegisterForm>(\n    (el) => {\n      if (!el) return;\n\n      formRef.current = el;\n      const form = formRef.current;\n\n      fieldsRef.current = getFields(form);\n      setNodesOrValues(initialStateRef.current.values);\n\n      handlersRef.current.change = ({ target }: Event) => {\n        const { name } = target as FieldElement;\n\n        if (fieldsRef.current.has(name) && !controlsRef.current[name]) {\n          const parse = fieldParsersRef.current[name]?.parse;\n          const value = getNodeValue(name);\n\n          handleChangeEvent(name, parse ? parse(value) : value);\n          changedFieldRef.current = name;\n        }\n      };\n\n      handlersRef.current.blur = ({ target }: Event) => {\n        if (!isFieldElement(target as HTMLElement)) return;\n\n        const { name } = target as FieldElement;\n\n        if (fieldsRef.current.has(name) && !controlsRef.current[name]) {\n          setTouchedMaybeValidate(name);\n          changedFieldRef.current = undefined;\n        }\n      };\n\n      handlersRef.current.submit = (e: Event) => submit(e as any);\n\n      handlersRef.current.reset = (e: Event) => reset(null, null, e as any);\n\n      form.addEventListener(\"input\", handlersRef.current.change);\n      form.addEventListener(\"focusout\", handlersRef.current.blur);\n      form.addEventListener(\"submit\", handlersRef.current.submit);\n      form.addEventListener(\"reset\", handlersRef.current.reset);\n\n      mutationObserverRef.current = new MutationObserver(([{ type }]) => {\n        if (type !== \"childList\") return;\n\n        const fields = getFields(form);\n        let { values } = initialStateRef.current;\n\n        fieldsRef.current.forEach((_, name) => {\n          if (!shouldRemoveField(name)) return;\n          if (controlsRef.current[name]) return;\n\n          if (!fields.has(name)) {\n            removeField(\n              name,\n              !isFieldArray(fieldArrayRef.current, name) ||\n                isUndefined(\n                  get(initialStateRef.current.values, name.split(\".\")[0])\n                )\n                ? undefined\n                : [\"defaultValue\"]\n            );\n\n            return;\n          }\n\n          const currOptions = fieldsRef.current.get(name)?.options\n            ?.length as number;\n          const nextOptions = fields.get(name).options?.length as number;\n\n          if (currOptions > nextOptions) {\n            setStateRef(`values.${name}`, getNodeValue(name, fields), {\n              shouldSkipUpdate: true,\n            });\n          } else if (currOptions < nextOptions) {\n            setNodeValue(name, get(values, name), fields);\n          }\n        });\n\n        const addedNodes: string[] = [];\n\n        fields.forEach((_, name) => {\n          if (fieldsRef.current.has(name) || controlsRef.current[name]) return;\n\n          const value = get(stateRef.current.values, name);\n          if (!isUndefined(value)) values = set(values, name, value, true);\n\n          addedNodes.push(name);\n        });\n\n        fieldsRef.current = fields;\n        if (addedNodes.length) setNodesOrValues(values, { fields: addedNodes });\n      });\n\n      mutationObserverRef.current.observe(form, {\n        childList: true,\n        subtree: true,\n      });\n    },\n    [\n      getFields,\n      getNodeValue,\n      handleChangeEvent,\n      removeField,\n      reset,\n      setNodeValue,\n      setNodesOrValues,\n      setStateRef,\n      setTouchedMaybeValidate,\n      shouldRemoveField,\n      stateRef,\n      submit,\n    ]\n  );\n\n  const registerField = useCallback<RegisterField<V>>(\n    (value) => (field) => {\n      if (\n        !field?.name ||\n        controlsRef.current[field.name] ||\n        excludeFieldsRef.current[field.name]\n      )\n        return;\n\n      if (isFunction(value)) {\n        fieldValidatorsRef.current[field.name] = value;\n        return;\n      }\n\n      const { validate: validator, ...parsers } = value;\n\n      if (validator) fieldValidatorsRef.current[field.name] = validator;\n      fieldParsersRef.current[field.name] = parsers;\n    },\n    []\n  );\n\n  shared.set(id, {\n    validateOnChange,\n    shouldRemoveField,\n    initialStateRef,\n    fieldArrayRef,\n    controlsRef,\n    observersRef,\n    fieldValidatorsRef,\n    changedFieldRef,\n    setStateRef,\n    getNodeValue,\n    getFormState,\n    setDefaultValue,\n    setNodesOrValues,\n    setTouchedMaybeValidate,\n    handleChangeEvent,\n    removeField,\n    form: registerForm,\n    field: registerField,\n    focus,\n    use,\n    getState,\n    setValue,\n    setTouched,\n    setDirty,\n    setError,\n    clearErrors,\n    runValidation,\n    reset,\n    submit,\n  });\n\n  useEffect(\n    () => () => {\n      if (formRef.current) {\n        const handlers = handlersRef.current as Required<Handlers>;\n\n        formRef.current.removeEventListener(\"input\", handlers.change);\n        formRef.current.removeEventListener(\"focusout\", handlers.blur);\n        formRef.current.removeEventListener(\"submit\", handlers.submit);\n        formRef.current.removeEventListener(\"reset\", handlers.reset);\n        mutationObserverRef.current?.disconnect();\n      }\n\n      shared.remove(id);\n    },\n    [id]\n  );\n\n  return {\n    form: registerForm,\n    field: registerField,\n    focus,\n    removeField,\n    use,\n    getState,\n    setValue,\n    setTouched,\n    setDirty,\n    setError,\n    clearErrors,\n    runValidation,\n    reset,\n    submit,\n  };\n};\n"
  },
  {
    "path": "src/useFormMethods.test.tsx",
    "content": "import { render } from \"@testing-library/react\";\n\nimport { FormMethods } from \"./types\";\nimport useForm from \"./useForm\";\nimport useFormMethods from \"./useFormMethods\";\n\ninterface Props {\n  children: (methods: FormMethods) => JSX.Element | null;\n  formId?: string;\n}\n\nconst Form = ({ children, formId }: Props) => {\n  const { form } = useForm({ id: formId });\n  const methods = useFormMethods(formId);\n\n  return <form ref={form}>{children(methods)}</form>;\n};\n\nconst renderHelper = (formId?: string) => {\n  let api: FormMethods;\n\n  render(\n    <Form formId={formId}>\n      {(methods) => {\n        api = methods;\n        return null;\n      }}\n    </Form>\n  );\n\n  // @ts-expect-error\n  return api;\n};\n\ndescribe(\"useFormMethods\", () => {\n  it(\"should throw form id errors\", () => {\n    expect(() => useFormMethods(\"form-1\")).toThrow(\n      '💡 react-cool-form > useFormMethods: It must work with an \"useForm\" hook. See: https://react-cool-form.netlify.app/docs/api-reference/use-form'\n    );\n  });\n\n  it.each([undefined, \"form-1\"])(\n    \"should return methods correctly\",\n    (formId) => {\n      const methods = renderHelper(formId);\n      expect(methods).toEqual({\n        form: expect.any(Function),\n        field: expect.any(Function),\n        focus: expect.any(Function),\n        removeField: expect.any(Function),\n        use: expect.any(Function),\n        getState: expect.any(Function),\n        setValue: expect.any(Function),\n        setTouched: expect.any(Function),\n        setDirty: expect.any(Function),\n        setError: expect.any(Function),\n        clearErrors: expect.any(Function),\n        runValidation: expect.any(Function),\n        reset: expect.any(Function),\n        submit: expect.any(Function),\n      });\n    }\n  );\n});\n"
  },
  {
    "path": "src/useFormMethods.ts",
    "content": "import { FormMethods, FormValues, Methods } from \"./types\";\nimport { get } from \"./shared\";\nimport { invariant } from \"./utils\";\n\nexport default <V extends FormValues = FormValues>(\n  formId?: string\n): FormMethods<V> => {\n  const methods: Methods<V> = get(formId);\n\n  invariant(\n    !methods,\n    '💡 react-cool-form > useFormMethods: It must work with an \"useForm\" hook. See: https://react-cool-form.netlify.app/docs/api-reference/use-form'\n  );\n\n  const {\n    form,\n    field,\n    focus,\n    removeField,\n    use,\n    getState,\n    setValue,\n    setTouched,\n    setDirty,\n    setError,\n    clearErrors,\n    runValidation,\n    reset,\n    submit,\n  } = methods;\n\n  return {\n    form,\n    field,\n    focus,\n    removeField,\n    use,\n    getState,\n    setValue,\n    setTouched,\n    setDirty,\n    setError,\n    clearErrors,\n    runValidation,\n    reset,\n    submit,\n  };\n};\n"
  },
  {
    "path": "src/useFormState.test.tsx",
    "content": "import { useEffect } from \"react\";\nimport { render, fireEvent, screen } from \"@testing-library/react\";\n\nimport { FormStateCallback, FormStateConfig, Path } from \"./types\";\nimport useForm from \"./useForm\";\nimport useFormState from \"./useFormState\";\n\nconst defaultValues = { foo: \"🍎\" };\nconst error = \"Required\";\n\ninterface Props extends FormStateConfig {\n  children: (props: any) => JSX.Element;\n  path?: Path;\n  formDefaultValues?: any;\n  errorVal?: string;\n  resetVal?: string;\n  isTouched?: boolean;\n  callback?: FormStateCallback;\n  onRender?: () => void;\n}\n\nconst Form = ({\n  children,\n  formId,\n  path,\n  formDefaultValues = defaultValues,\n  errorVal,\n  resetVal,\n  isTouched,\n  callback,\n  onRender = () => null,\n  ...rest\n}: Props) => {\n  const { form, setError, setTouched, reset } = useForm({\n    id: formId,\n    defaultValues: formDefaultValues,\n  });\n  // @ts-expect-error\n  const props = useFormState(path, callback || { ...rest, formId }, formId);\n\n  onRender();\n\n  useEffect(() => {\n    if (errorVal) setError(\"foo\", errorVal);\n    if (resetVal) reset({ foo: resetVal });\n    if (isTouched) setTouched(\"foo\");\n  }, [errorVal, isTouched, reset, resetVal, setError, setTouched]);\n\n  return <form ref={form}>{children(props)}</form>;\n};\n\nconst renderHelper = (args: Omit<Props, \"children\"> = {}) => {\n  let props;\n\n  render(\n    <Form {...args}>\n      {(p) => {\n        props = p;\n        return <input data-testid=\"foo\" name=\"foo\" />;\n      }}\n    </Form>\n  );\n\n  return props;\n};\n\ndescribe(\"useFormState\", () => {\n  it(\"should throw form id errors\", () => {\n    expect(() => useFormState(\"values\", { formId: \"form-1\" })).toThrow(\n      '💡 react-cool-form > useFormState: It must work with an \"useForm\" hook. See: https://react-cool-form.netlify.app/docs/api-reference/use-form'\n    );\n  });\n\n  it('should warn watch \"values\" alone', () => {\n    console.warn = jest.fn();\n    renderHelper({ path: \"values\" });\n    expect(console.warn).toHaveBeenCalledWith(\n      '💡 react-cool-form > useFormState: Getting \"values\" alone might cause unnecessary re-renders. If you know what you\\'re doing, just ignore this warning. See: https://react-cool-form.netlify.app/docs/getting-started/form-state#best-practices'\n    );\n  });\n\n  it.each([\"path\", \"callback\"])(\n    'should not warn watch \"values\" alone when %s is set',\n    (type) => {\n      console.warn = jest.fn();\n      renderHelper({\n        path: type === \"path\" ? \"values.foo\" : \"values\",\n        callback: type === \"callback\" ? () => null : undefined,\n      });\n      expect(console.warn).not.toHaveBeenCalled();\n    }\n  );\n\n  it('should return undefined if \"path\" isn\\'t set', () => {\n    const props = renderHelper();\n    expect(props).toBeUndefined();\n  });\n\n  it('should not trigger callback if \"path\" isn\\'t set', () => {\n    const callback = jest.fn();\n    renderHelper({ callback });\n    fireEvent.input(screen.getByTestId(\"foo\"));\n    expect(callback).not.toHaveBeenCalled();\n  });\n\n  it(\"should get default value correctly\", () => {\n    const formDefaultValues = { foo: null };\n    expect(renderHelper({ path: \"values.foo\", formDefaultValues })).toBe(\n      formDefaultValues.foo\n    );\n\n    expect(\n      renderHelper({\n        path: \"values.foo\",\n        formDefaultValues,\n        defaultValues,\n      })\n    ).toBe(formDefaultValues.foo);\n\n    expect(renderHelper({ path: \"values.foo\", defaultValues })).toBe(\n      defaultValues.foo\n    );\n  });\n\n  it(\"should get reset value correctly\", () => {\n    const resetVal = \"🍎\";\n    expect(renderHelper({ path: \"values.foo\", resetVal })).toBe(resetVal);\n  });\n\n  it(\"should get state with correct format\", () => {\n    expect(renderHelper({ path: \"values\" })).toEqual(defaultValues);\n    expect(renderHelper({ path: \"values.foo\" })).toBe(defaultValues.foo);\n    expect(renderHelper({ path: \"isValid\" })).toBeTruthy();\n\n    expect(renderHelper({ path: [\"values\", \"values.foo\", \"isValid\"] })).toEqual(\n      [defaultValues, defaultValues.foo, true]\n    );\n\n    expect(\n      renderHelper({\n        path: {\n          values: \"values\",\n          foo: \"values.foo\",\n          isValid: \"isValid\",\n        },\n      })\n    ).toEqual({\n      values: defaultValues,\n      foo: defaultValues.foo,\n      isValid: true,\n    });\n  });\n\n  it(\"should get form's values by shortcut\", () => {\n    const { foo } = defaultValues;\n    expect(renderHelper({ path: \"foo\" })).toBe(foo);\n    expect(renderHelper({ path: [\"foo\"] })).toEqual([foo]);\n    expect(renderHelper({ path: { foo: \"foo\" } })).toEqual({ foo });\n  });\n\n  it(\"should get error with touched\", () => {\n    const args = { path: \"errors.foo\", errorVal: error };\n\n    expect(renderHelper(args)).not.toBeUndefined();\n\n    expect(renderHelper({ ...args, errorWithTouched: true })).toBeUndefined();\n\n    expect(\n      renderHelper({ ...args, errorWithTouched: true, isTouched: true })\n    ).toBe(error);\n  });\n\n  it(\"should work with form ID\", () => {\n    const config = { path: \"foo\", formId: \"form-1\" };\n    const { foo } = defaultValues;\n    expect(renderHelper(config)).toBe(foo);\n    expect(renderHelper({ ...config, callback: () => null })).toBe(foo);\n  });\n\n  it(\"should trigger re-rendering\", () => {\n    const onRender = jest.fn();\n    renderHelper({ path: \"values.foo\", onRender });\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value: \"🍋\" } });\n    expect(onRender).toHaveBeenCalledTimes(2);\n  });\n\n  it(\"should trigger callback correctly\", () => {\n    const onRender = jest.fn();\n    const callback = jest.fn();\n    const value = \"🍋\";\n    renderHelper({ path: \"values.foo\", onRender, callback });\n    fireEvent.input(screen.getByTestId(\"foo\"), { target: { value } });\n    expect(callback).toHaveBeenCalledWith(value);\n    expect(onRender).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "src/useFormState.ts",
    "content": "/* eslint-disable react-hooks/rules-of-hooks */\n\nimport { useEffect, useReducer, useRef } from \"react\";\n\nimport {\n  FormStateCallback,\n  FormStateConfig,\n  FormValues,\n  Methods,\n  Observer,\n  Path,\n} from \"./types\";\nimport { get } from \"./shared\";\nimport { invariant, isFunction, parseState } from \"./utils\";\n\nexport default <V extends FormValues = FormValues>(\n  path: Path,\n  configOrCallback: FormStateCallback | FormStateConfig<V>,\n  formId?: string\n): any => {\n  const config = !isFunction(configOrCallback) ? configOrCallback : {};\n  const methods: Methods<V> = get(config?.formId || formId);\n\n  invariant(\n    !methods,\n    `💡 react-cool-form > useFormState: It must work with an \"useForm\" hook. See: https://react-cool-form.netlify.app/docs/api-reference/use-form`\n  );\n\n  const observerRef = useRef<Observer<V>>();\n  const [, forceUpdate] = useReducer((c) => c + 1, 0);\n  const { observersRef, getFormState } = methods;\n  const callback = isFunction(configOrCallback) ? configOrCallback : undefined;\n\n  useEffect(() => {\n    observersRef.current.push(observerRef.current!);\n\n    return () => {\n      observersRef.current = observersRef.current.filter(\n        (o) => o !== observerRef.current\n      );\n    };\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []);\n\n  return getFormState(path, {\n    ...config,\n    methodName: callback ? \"useFormStateCallback\" : \"useFormState\",\n    callback: (usedState) => {\n      if (!observerRef.current)\n        observerRef.current = {\n          usedState,\n          notify: callback\n            ? (state) => callback(parseState(path, state))\n            : forceUpdate,\n        };\n    },\n  });\n};\n"
  },
  {
    "path": "src/utils/arrayToMap.test.ts",
    "content": "import arrayToMap from \"./arrayToMap\";\n\ndescribe(\"arrayToMap\", () => {\n  it(\"should work correctly\", () => {\n    expect(arrayToMap([\"🍎\", \"🍋\", \"🥝\"], { \"🍎\": \"🍒\" })).toEqual({\n      \"🍒\": true,\n      \"🍋\": true,\n      \"🥝\": true,\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/arrayToMap.ts",
    "content": "import { ObjMap } from \"../types\";\n\nexport default (arr: any[], map: Record<string, string> = {}): ObjMap =>\n  arr.reduce((obj, key) => {\n    obj[map[key] || key] = true;\n    return obj;\n  }, {});\n"
  },
  {
    "path": "src/utils/cloneObject.test.ts",
    "content": "import cloneObject from \"./cloneObject\";\n\ndescribe(\"cloneObject\", () => {\n  it(\"should throw error when target is an event\", () => {\n    expect(() => cloneObject(new Event(\"🍎\"))).toThrow(Error);\n  });\n\n  it(\"should work correctly\", () => {\n    let target: any = {\n      foo: undefined,\n      bar: null,\n      baz: true,\n      qux: 1,\n      quux: \"🍎\",\n      quuz: [\"🍎\", [\"🍎\"]],\n      corge: { foo: \"🍎\" },\n      fred: new Date(),\n      waldo: () => null,\n      xyzzy: NaN,\n    };\n    expect(cloneObject(target)).toEqual(target);\n\n    target = { foo: { bar: target } };\n    expect(cloneObject(target)).toEqual(target);\n  });\n\n  it(\"should return new object\", () => {\n    const target = { foo: \"🍎\" };\n    expect(cloneObject(target)).not.toBe(target);\n  });\n});\n"
  },
  {
    "path": "src/utils/cloneObject.ts",
    "content": "import isFileList from \"./isFileList\";\nimport isObject from \"./isObject\";\n\nconst cloneObject = (object: unknown): any => {\n  if (object instanceof Event) throw new Error(\"Unable to clone event.\");\n\n  if (!isObject(object) || isFileList(object)) return object;\n\n  if (object instanceof Date) return new Date(object.getTime());\n\n  if (Array.isArray(object)) return object.map((val) => cloneObject(val));\n\n  return Object.keys(object).reduce((obj: Record<string, any>, key) => {\n    obj[key] = cloneObject((object as Record<string, any>)[key]);\n    return obj;\n  }, {});\n};\n\nexport default cloneObject;\n"
  },
  {
    "path": "src/utils/compact.test.ts",
    "content": "import compact from \"./compact\";\n\ndescribe(\"compact\", () => {\n  it(\"should work correctly\", () => {\n    expect(compact([true, \"0\", 1, [], {}])).toEqual([true, \"0\", 1, [], {}]);\n    expect(compact([undefined, null, false, NaN, \"\", 0])).toEqual([]);\n  });\n});\n"
  },
  {
    "path": "src/utils/compact.ts",
    "content": "export default (arr: any[]): any[] => arr.filter(Boolean);\n"
  },
  {
    "path": "src/utils/deepMerge.test.ts",
    "content": "import deepMerge from \"./deepMerge\";\n\ndescribe(\"deepMerge\", () => {\n  it(\"should merge different types of values correctly\", () => {\n    let target: any = { foo: { bar: [] } };\n    let override: any = { foo: { bar: {} } };\n    expect(deepMerge(target, override)).toEqual(override);\n    target = { foo: { bar: {} } };\n    override = { foo: { bar: [] } };\n    expect(deepMerge(target, override)).toEqual(override);\n    override = { foo: { bar: null } };\n    expect(deepMerge(target, override)).toEqual(override);\n    override = { foo: { bar: undefined } };\n    expect(deepMerge(target, override)).toEqual(override);\n    override = { foo: { bar: NaN } };\n    expect(deepMerge(target, override)).toEqual(override);\n    override = { foo: { bar: true } };\n    expect(deepMerge(target, override)).toEqual(override);\n    override = { foo: { bar: \"\" } };\n    expect(deepMerge(target, override)).toEqual(override);\n    override = { foo: { bar: 1 } };\n    expect(deepMerge(target, override)).toEqual(override);\n    override = { foo: { bar: new Date() } };\n    expect(deepMerge(target, override)).toEqual(override);\n  });\n\n  it(\"should merge dates correctly\", () => {\n    const override = { foo: { bar: new Date(\"2021-01-09\") } };\n    expect(deepMerge({ foo: { bar: new Date() } }, override)).toEqual(override);\n  });\n\n  it(\"should merge objects correctly\", () => {\n    let target: any = { foo: { bar: {} } };\n    let override: any = { foo: { bar: { a: \"🍎\" } } };\n    expect(deepMerge(target, override)).toEqual(override);\n    target = { foo: { bar: { a: \"🍋\" } } };\n    override = { foo: { bar: { a: \"🍎\" } } };\n    expect(deepMerge(target, override)).toEqual(override);\n    override = { foo: { bar: { b: \"🍎\" } } };\n    expect(deepMerge(target, override)).toEqual({\n      foo: { bar: { a: \"🍋\", b: \"🍎\" } },\n    });\n  });\n\n  it(\"should merge arrays correctly\", () => {\n    let target: any = { foo: { bar: [] } };\n    let override: any = { foo: { bar: [\"🍎\"] } };\n    expect(deepMerge(target, override)).toEqual(override);\n    target = { foo: { bar: [\"🍋\"] } };\n    override = { foo: { bar: [\"🍎\"] } };\n    expect(deepMerge(target, override)).toEqual({ foo: { bar: [\"🍋\", \"🍎\"] } });\n    target = { foo: { bar: [{}] } };\n    override = { foo: { bar: [[]] } };\n    expect(deepMerge(target, override)).toEqual({ foo: { bar: [{}, []] } });\n    target = { foo: { bar: [{ a: \"🍋\" }] } };\n    override = { foo: { bar: [{ a: \"🍎\" }] } };\n    expect(deepMerge(target, override)).toEqual({\n      foo: { bar: [{ a: \"🍋\" }, { a: \"🍎\" }] },\n    });\n    target = { foo: { bar: [[\"🍋\"]] } };\n    override = { foo: { bar: [[\"🍎\"]] } };\n    expect(deepMerge(target, override)).toEqual({\n      foo: { bar: [[\"🍋\"], [\"🍎\"]] },\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/deepMerge.ts",
    "content": "import isPlainObject from \"./isPlainObject\";\n\nconst deepMerge = (...objects: any[]): any =>\n  objects.reduce((prev, obj) => {\n    Object.keys(obj).forEach((key) => {\n      const prevValue = prev[key];\n      const currValue = obj[key];\n\n      if (Array.isArray(prevValue) && Array.isArray(currValue)) {\n        prev[key] = [...prevValue, ...currValue];\n      } else if (isPlainObject(prevValue) && isPlainObject(currValue)) {\n        prev[key] = deepMerge(prevValue, currValue);\n      } else {\n        prev[key] = currValue;\n      }\n    });\n\n    return prev;\n  }, {});\n\nexport default deepMerge;\n"
  },
  {
    "path": "src/utils/filterErrors.test.ts",
    "content": "import filterErrors from \"./filterErrors\";\n\ndescribe(\"filterErrors\", () => {\n  it(\"should work correctly\", () => {\n    expect(filterErrors(undefined, false)).toBeUndefined();\n    expect(filterErrors(undefined, false)).toBeUndefined();\n    expect(filterErrors({}, false)).toEqual({});\n    expect(filterErrors(\"🍎\", false)).toBeUndefined();\n    expect(filterErrors(\"🍎\", true)).toBe(\"🍎\");\n    expect(filterErrors({ foo: \"🍎\" }, { foo: true })).toEqual({ foo: \"🍎\" });\n    expect(filterErrors({ foo: \"🍎\" }, {})).toEqual({});\n    const foo = new Date();\n    expect(filterErrors({ foo }, { foo: true })).toEqual({ foo });\n  });\n});\n"
  },
  {
    "path": "src/utils/filterErrors.ts",
    "content": "import { ObjMap } from \"../types\";\nimport isPlainObject from \"./isPlainObject\";\nimport isUndefined from \"./isUndefined\";\n\nconst filterErrors = (error: unknown, touched: unknown): any => {\n  if (!isPlainObject(error)) return touched ? error : undefined;\n\n  return Object.keys(error).reduce((obj: ObjMap<any>, key) => {\n    const nextErrors = filterErrors(\n      (error as ObjMap<any>)[key],\n      (touched as ObjMap<any>)[key] || false\n    );\n\n    if (!isUndefined(nextErrors)) {\n      obj[key] = nextErrors;\n    } else {\n      delete obj[key];\n    }\n\n    return obj;\n  }, {});\n};\n\nexport default filterErrors;\n"
  },
  {
    "path": "src/utils/get.test.ts",
    "content": "import get from \"./get\";\n\ndescribe(\"get\", () => {\n  it('should return \"undefined\" when target is invalid', () => {\n    expect(get(null, \"foo\")).toBeUndefined();\n    expect(get(undefined, \"foo\")).toBeUndefined();\n    expect(get(NaN, \"foo\")).toBeUndefined();\n    expect(get(true, \"foo\")).toBeUndefined();\n    expect(get(\"\", \"foo\")).toBeUndefined();\n    expect(get(1, \"foo\")).toBeUndefined();\n    expect(get([], \"foo\")).toBeUndefined();\n    expect(get(new Date(), \"foo\")).toBeUndefined();\n    expect(get(() => null, \"foo\")).toBeUndefined();\n  });\n\n  it('should return \"undefined\" when path is invalid', () => {\n    // @ts-ignore\n    expect(get({}, null)).toBeUndefined();\n    // @ts-ignore\n    expect(get({}, undefined)).toBeUndefined();\n    expect(get({}, \"\")).toBeUndefined();\n  });\n\n  it(\"should return default value if property not found\", () => {\n    expect(get({}, \"foo\", \"🍎\")).toBe(\"🍎\");\n    expect(get({ foo: [] }, \"foo.0\", \"🍎\")).toBe(\"🍎\");\n    expect(get({ foo: [] }, \"foo[0]\", \"🍎\")).toBe(\"🍎\");\n    expect(get({ foo: [] }, \"foo.bar\", \"🍎\")).toBe(\"🍎\");\n    expect(get({ foo: [{}] }, \"foo.0.bar\", \"🍎\")).toBe(\"🍎\");\n    expect(get({ foo: [{}] }, \"foo[0].bar\", \"🍎\")).toBe(\"🍎\");\n  });\n\n  it(\"should get value by keys\", () => {\n    expect(get({ foo: \"🍎\" }, \"foo\")).toBe(\"🍎\");\n    expect(get({ foo: { bar: \"🍎\" } }, \"foo.bar\")).toBe(\"🍎\");\n    expect(get({ foo: { bar: { baz: \"🍎\" } } }, \"foo.bar.baz\")).toBe(\"🍎\");\n  });\n\n  it(\"should get value by indexes\", () => {\n    expect(get({ foo: [\"🍎\"] }, \"foo.0\")).toBe(\"🍎\");\n    expect(get({ foo: [\"🍋\", \"🍎\"] }, \"foo.1\")).toBe(\"🍎\");\n    expect(get({ foo: [[\"🍎\"]] }, \"foo.0.0\")).toBe(\"🍎\");\n    expect(get({ foo: [[\"🍋\", \"🍎\"]] }, \"foo.0.1\")).toBe(\"🍎\");\n\n    expect(get({ foo: [\"🍎\"] }, \"foo[0]\")).toBe(\"🍎\");\n    expect(get({ foo: [\"🍋\", \"🍎\"] }, \"foo[1]\")).toBe(\"🍎\");\n    expect(get({ foo: [[\"🍎\"]] }, \"foo[0][0]\")).toBe(\"🍎\");\n    expect(get({ foo: [[\"🍋\", \"🍎\"]] }, \"foo[0][1]\")).toBe(\"🍎\");\n  });\n\n  it(\"should get value by mixed\", () => {\n    expect(get({ foo: { bar: [[\"🍋\", \"🍎\"]] } }, \"foo.bar[0].1\")).toBe(\"🍎\");\n    expect(get({ foo: [{ bar: [\"🍋\", \"🍎\"] }] }, \"foo.0.bar[1]\")).toBe(\"🍎\");\n    expect(get({ foo: [[\"🍋\", { bar: \"🍎\" }]] }, \"foo[0].1.bar\")).toBe(\"🍎\");\n    expect(get({ foo: [, { bar: [{ baz: \"🍎\" }] }] }, \"foo.1.bar[0].baz\")).toBe(\n      \"🍎\"\n    );\n  });\n\n  it(\"should return falsy values correctly\", () => {\n    expect(get({ foo: null }, \"foo\")).toBeNull();\n    expect(get({ foo: false }, \"foo\")).toBeFalsy();\n    expect(get({ foo: 0 }, \"foo\")).toBe(0);\n    expect(get({ foo: \"\" }, \"foo\")).toBe(\"\");\n  });\n});\n"
  },
  {
    "path": "src/utils/get.ts",
    "content": "import isPlainObject from \"./isPlainObject\";\nimport isUndefined from \"./isUndefined\";\nimport stringToPath from \"./stringToPath\";\n\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nexport default (object: any, path: string, defaultValue?: unknown): any => {\n  if (!isPlainObject(object) || !path) return defaultValue;\n\n  const value = stringToPath(path).reduce(\n    (obj, key) => (obj || {})[key],\n    object\n  );\n\n  return !isUndefined(value) ? value : defaultValue;\n};\n"
  },
  {
    "path": "src/utils/getIsDirty.test.ts",
    "content": "import getIsDirty from \"./getIsDirty\";\n\ndescribe(\"getIsDirty\", () => {\n  it(\"should work correctly\", () => {\n    expect(getIsDirty({})).toBeFalsy();\n    expect(getIsDirty({ foo: true })).toBeTruthy();\n    expect(getIsDirty({ foo: [true] })).toBeTruthy();\n    expect(getIsDirty({ foo: {} })).toBeFalsy();\n    expect(getIsDirty({ foo: { bar: { baz: true } } })).toBeTruthy();\n    expect(getIsDirty({ foo: { bar: { baz: [true] } } })).toBeTruthy();\n    expect(getIsDirty({ foo: { bar: {} } })).toBeFalsy();\n    expect(getIsDirty({ foo: { bar: [{ baz: true }] } })).toBeTruthy();\n    expect(getIsDirty({ foo: { bar: [{ baz: [true] }] } })).toBeTruthy();\n    expect(getIsDirty({})).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "src/utils/getIsDirty.ts",
    "content": "import isObject from \"./isObject\";\n\nexport default (dirty: object): boolean => {\n  const search = (dty: object, found: any[] = []) => {\n    for (const val of Object.values(dty)) {\n      if (val === true) {\n        found.push(val);\n        return found;\n      }\n\n      if (isObject(val)) search(val, found);\n    }\n\n    return found;\n  };\n\n  return !!search(dirty).length;\n};\n"
  },
  {
    "path": "src/utils/getPath.test.ts",
    "content": "import getPath from \"./getPath\";\n\ndescribe(\"getPath\", () => {\n  it(\"should work correctly\", () => {\n    expect(getPath(\"foo\")).toBe(\"values.foo\");\n    expect(getPath(\"values.foo\")).toBe(\"values.foo\");\n    expect(getPath(\"touched.foo\")).toBe(\"touched.foo\");\n    expect(getPath(\"errors.foo\")).toBe(\"errors.foo\");\n    expect(getPath(\"dirty.foo\")).toBe(\"dirty.foo\");\n    expect(getPath(\"isDirty\")).toBe(\"isDirty\");\n    expect(getPath(\"isValid\")).toBe(\"isValid\");\n    expect(getPath(\"isSubmitting\")).toBe(\"isSubmitting\");\n    expect(getPath(\"isSubmitted\")).toBe(\"isSubmitted\");\n    expect(getPath(\"submitCount\")).toBe(\"submitCount\");\n  });\n});\n"
  },
  {
    "path": "src/utils/getPath.ts",
    "content": "export default (path: string): string =>\n  ![\n    \"values\",\n    \"touched\",\n    \"errors\",\n    \"isDirty\",\n    \"dirty\",\n    \"isValidating\",\n    \"isValid\",\n    \"isSubmitting\",\n    \"isSubmitted\",\n    \"submitCount\",\n  ].some((key) => path.startsWith(key))\n    ? `values.${path}`\n    : path;\n"
  },
  {
    "path": "src/utils/index.ts",
    "content": "export { default as arrayToMap } from \"./arrayToMap\";\nexport { default as cloneObject } from \"./cloneObject\";\nexport { default as compact } from \"./compact\";\nexport { default as deepMerge } from \"./deepMerge\";\nexport { default as filterErrors } from \"./filterErrors\";\nexport { default as get } from \"./get\";\nexport { default as getIsDirty } from \"./getIsDirty\";\nexport { default as getPath } from \"./getPath\";\nexport { default as invariant } from \"./invariant\";\nexport { default as isAsyncFunction } from \"./isAsyncFunction\";\nexport { default as isCheckboxInput } from \"./isCheckboxInput\";\nexport { default as isEmptyObject } from \"./isEmptyObject\";\nexport { default as isFieldArray } from \"./isFieldArray\";\nexport { default as isFieldElement } from \"./isFieldElement\";\nexport { default as isFileInput } from \"./isFileInput\";\nexport { default as isFileList } from \"./isFileList\";\nexport { default as isFunction } from \"./isFunction\";\nexport { default as isInputElement } from \"./isInputElement\";\nexport { default as isNumberInput } from \"./isNumberInput\";\nexport { default as isObject } from \"./isObject\";\nexport { default as isPlainObject } from \"./isPlainObject\";\nexport { default as isRadioInput } from \"./isRadioInput\";\nexport { default as isRangeInput } from \"./isRangeInput\";\nexport { default as isSelectMultiple } from \"./isSelectMultiple\";\nexport { default as isSelectOne } from \"./isSelectOne\";\nexport { default as isUndefined } from \"./isUndefined\";\nexport { default as parseState } from \"./parseState\";\nexport { default as runWithLowPriority } from \"./runWithLowPriority\";\nexport { default as set } from \"./set\";\nexport { default as setValuesAsTrue } from \"./setValuesAsTrue\";\nexport { default as stringToPath } from \"./stringToPath\";\nexport { default as unset } from \"./unset\";\nexport { default as warn } from \"./warn\";\n"
  },
  {
    "path": "src/utils/invariant.test.ts",
    "content": "import invariant from \"./invariant\";\n\ndescribe(\"invariant\", () => {\n  it(\"should work correctly\", () => {\n    const message = \"Oops!\";\n    expect(() => invariant(true, message)).toThrow(message);\n    expect(() => invariant(false, message)).not.toThrow();\n\n    // @ts-expect-error\n    global.__DEV__ = false;\n    expect(() => invariant(true, message)).not.toThrow();\n  });\n});\n"
  },
  {
    "path": "src/utils/invariant.ts",
    "content": "export default (condition: boolean, message: string): void => {\n  if (__DEV__ && condition) throw new Error(message);\n};\n"
  },
  {
    "path": "src/utils/isAsyncFunction.test.ts",
    "content": "import isAsyncFunction from \"./isAsyncFunction\";\n\ndescribe(\"isAsyncFunction\", () => {\n  it(\"should work correctly\", () => {\n    expect(isAsyncFunction(undefined)).toBeFalsy();\n    expect(isAsyncFunction(null)).toBeFalsy();\n    expect(isAsyncFunction(NaN)).toBeFalsy();\n    expect(isAsyncFunction(true)).toBeFalsy();\n    expect(isAsyncFunction(1)).toBeFalsy();\n    expect(isAsyncFunction(\"\")).toBeFalsy();\n    expect(isAsyncFunction([])).toBeFalsy();\n    expect(isAsyncFunction({})).toBeFalsy();\n    expect(isAsyncFunction(new Date())).toBeFalsy();\n    expect(isAsyncFunction(() => null)).toBeFalsy();\n    expect(isAsyncFunction(async () => null)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isAsyncFunction.ts",
    "content": "import isFunction from \"./isFunction\";\n\nexport default (value: unknown): value is Promise<any> =>\n  isFunction(value) && value.constructor.name === \"AsyncFunction\";\n"
  },
  {
    "path": "src/utils/isCheckboxInput.test.ts",
    "content": "import isCheckboxInput from \"./isCheckboxInput\";\n\ndescribe(\"isCheckboxInput\", () => {\n  it(\"should work correctly\", () => {\n    const input = document.createElement(\"input\");\n    expect(isCheckboxInput(input)).toBeFalsy();\n    input.type = \"checkbox\";\n    expect(isCheckboxInput(input)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isCheckboxInput.ts",
    "content": "import { FieldElement } from \"../types\";\n\nexport default (field: FieldElement): field is HTMLInputElement =>\n  field.type === \"checkbox\";\n"
  },
  {
    "path": "src/utils/isEmptyObject.test.ts",
    "content": "import isEmptyObject from \"./isEmptyObject\";\n\ndescribe(\"isEmptyObject\", () => {\n  it(\"should work correctly\", () => {\n    expect(isEmptyObject(undefined)).toBeFalsy();\n    expect(isEmptyObject(null)).toBeFalsy();\n    expect(isEmptyObject(NaN)).toBeFalsy();\n    expect(isEmptyObject(true)).toBeFalsy();\n    expect(isEmptyObject(1)).toBeFalsy();\n    expect(isEmptyObject(\"\")).toBeFalsy();\n    expect(isEmptyObject(new Date())).toBeFalsy();\n    expect(isEmptyObject(() => null)).toBeFalsy();\n    expect(isEmptyObject([])).toBeFalsy();\n    expect(isEmptyObject({ test: \"\" })).toBeFalsy();\n    expect(isEmptyObject({})).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isEmptyObject.ts",
    "content": "import { ObjMap } from \"../types\";\nimport isPlainObject from \"./isPlainObject\";\n\nexport default (value: unknown): value is ObjMap<never> =>\n  isPlainObject(value) && !Object.keys(value).length;\n"
  },
  {
    "path": "src/utils/isFieldArray.test.ts",
    "content": "import isFieldArray from \"./isFieldArray\";\n\ndescribe(\"isFieldArray\", () => {\n  it(\"should work correctly\", () => {\n    // @ts-expect-error\n    expect(isFieldArray({ foo: true }, \"foo[0].a\")).toBe(\"foo\");\n\n    // @ts-expect-error\n    expect(isFieldArray({ foo: true }, \"bar[0].a\")).toBeUndefined();\n\n    let callback = jest.fn();\n    // @ts-expect-error\n    isFieldArray({ foo: true }, \"foo[0].a\", callback);\n    expect(callback).toHaveBeenCalledWith(\"foo\");\n\n    callback = jest.fn();\n    // @ts-expect-error\n    isFieldArray({ foo: true }, \"bar[0].a\", callback);\n    expect(callback).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "src/utils/isFieldArray.ts",
    "content": "import { FieldArray } from \"../types\";\n\nexport default (\n  fields: FieldArray,\n  name: string,\n  callback?: (key: string) => void\n): string | void => {\n  let fieldName;\n\n  Object.keys(fields).some((key) => {\n    if (name.startsWith(key)) {\n      fieldName = key;\n      if (callback) callback(key);\n      return true;\n    }\n    return false;\n  });\n\n  return fieldName;\n};\n"
  },
  {
    "path": "src/utils/isFieldElement.test.ts",
    "content": "import isFieldElement from \"./isFieldElement\";\n\ndescribe(\"isFieldElement\", () => {\n  it(\"should work correctly\", () => {\n    expect(isFieldElement(document.createElement(\"div\"))).toBeFalsy();\n    expect(isFieldElement(document.createElement(\"input\"))).toBeTruthy();\n    expect(isFieldElement(document.createElement(\"textarea\"))).toBeTruthy();\n    expect(isFieldElement(document.createElement(\"select\"))).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isFieldElement.ts",
    "content": "import { FieldElement } from \"../types\";\n\nexport default (element: HTMLElement): element is FieldElement =>\n  /INPUT|TEXTAREA|SELECT/.test(element.tagName);\n"
  },
  {
    "path": "src/utils/isFileInput.test.ts",
    "content": "import isFileInput from \"./isFileInput\";\n\ndescribe(\"isFileInput\", () => {\n  it(\"should work correctly\", () => {\n    const input = document.createElement(\"input\");\n    expect(isFileInput(input)).toBeFalsy();\n    input.type = \"file\";\n    expect(isFileInput(input)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isFileInput.ts",
    "content": "import { FieldElement } from \"../types\";\n\nexport default (field: FieldElement): field is HTMLInputElement =>\n  field.type === \"file\";\n"
  },
  {
    "path": "src/utils/isFileList.ts",
    "content": "export default (value: unknown): value is FileList => value instanceof FileList;\n"
  },
  {
    "path": "src/utils/isFunction.test.ts",
    "content": "import isFunction from \"./isFunction\";\n\ndescribe(\"isFunction\", () => {\n  it(\"should work correctly\", () => {\n    expect(isFunction(undefined)).toBeFalsy();\n    expect(isFunction(null)).toBeFalsy();\n    expect(isFunction(NaN)).toBeFalsy();\n    expect(isFunction(true)).toBeFalsy();\n    expect(isFunction(1)).toBeFalsy();\n    expect(isFunction(\"\")).toBeFalsy();\n    expect(isFunction([])).toBeFalsy();\n    expect(isFunction({})).toBeFalsy();\n    expect(isFunction(new Date())).toBeFalsy();\n    expect(isFunction(() => null)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isFunction.ts",
    "content": "export default (value: unknown): value is Function =>\n  typeof value === \"function\";\n"
  },
  {
    "path": "src/utils/isInputElement.test.ts",
    "content": "import isInputElement from \"./isInputElement\";\n\ndescribe(\"isInputElement\", () => {\n  it(\"should work correctly\", () => {\n    expect(isInputElement(document.createElement(\"div\"))).toBeFalsy();\n    expect(isInputElement(document.createElement(\"input\"))).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isInputElement.ts",
    "content": "export default (element: HTMLElement): element is HTMLInputElement =>\n  element.tagName === \"INPUT\";\n"
  },
  {
    "path": "src/utils/isNumberInput.test.ts",
    "content": "import isNumberInput from \"./isNumberInput\";\n\ndescribe(\"isNumberInput\", () => {\n  it(\"should work correctly\", () => {\n    const input = document.createElement(\"input\");\n    expect(isNumberInput(input)).toBeFalsy();\n    input.type = \"number\";\n    expect(isNumberInput(input)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isNumberInput.ts",
    "content": "import { FieldElement } from \"../types\";\n\nexport default (field: FieldElement): field is HTMLInputElement =>\n  field.type === \"number\";\n"
  },
  {
    "path": "src/utils/isObject.test.ts",
    "content": "import isObject from \"./isObject\";\n\ndescribe(\"isObject\", () => {\n  it(\"should work correctly\", () => {\n    expect(isObject(undefined)).toBeFalsy();\n    expect(isObject(null)).toBeFalsy();\n    expect(isObject(NaN)).toBeFalsy();\n    expect(isObject(true)).toBeFalsy();\n    expect(isObject(1)).toBeFalsy();\n    expect(isObject(\"\")).toBeFalsy();\n    expect(isObject(() => null)).toBeFalsy();\n    expect(isObject(new Date())).toBeTruthy();\n    expect(isObject([])).toBeTruthy();\n    expect(isObject({})).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isObject.ts",
    "content": "export default (value: unknown): value is Object =>\n  value !== null && typeof value === \"object\";\n"
  },
  {
    "path": "src/utils/isPlainObject.test.ts",
    "content": "import isPlainObject from \"./isPlainObject\";\n\ndescribe(\"isPlainObject\", () => {\n  it(\"should work correctly\", () => {\n    expect(isPlainObject(undefined)).toBeFalsy();\n    expect(isPlainObject(null)).toBeFalsy();\n    expect(isPlainObject(NaN)).toBeFalsy();\n    expect(isPlainObject(true)).toBeFalsy();\n    expect(isPlainObject(1)).toBeFalsy();\n    expect(isPlainObject(\"\")).toBeFalsy();\n    expect(isPlainObject(new Date())).toBeFalsy();\n    expect(isPlainObject(() => null)).toBeFalsy();\n    expect(isPlainObject([])).toBeFalsy();\n    expect(isPlainObject({})).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isPlainObject.ts",
    "content": "import isObject from \"./isObject\";\n\nexport default (value: unknown): value is Object =>\n  !Array.isArray(value) && !(value instanceof Date) && isObject(value);\n"
  },
  {
    "path": "src/utils/isRadioInput.test.ts",
    "content": "import isRadioInput from \"./isRadioInput\";\n\ndescribe(\"isRadioInput\", () => {\n  it(\"should work correctly\", () => {\n    const input = document.createElement(\"input\");\n    expect(isRadioInput(input)).toBeFalsy();\n    input.type = \"radio\";\n    expect(isRadioInput(input)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isRadioInput.ts",
    "content": "import { FieldElement } from \"../types\";\n\nexport default (field: FieldElement): field is HTMLInputElement =>\n  field.type === \"radio\";\n"
  },
  {
    "path": "src/utils/isRangeInput.test.ts",
    "content": "import isRangeInput from \"./isRangeInput\";\n\ndescribe(\"isRangeInput\", () => {\n  it(\"should work correctly\", () => {\n    const input = document.createElement(\"input\");\n    expect(isRangeInput(input)).toBeFalsy();\n    input.type = \"range\";\n    expect(isRangeInput(input)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isRangeInput.ts",
    "content": "import { FieldElement } from \"../types\";\n\nexport default (field: FieldElement): field is HTMLInputElement =>\n  field.type === \"range\";\n"
  },
  {
    "path": "src/utils/isSelectMultiple.test.ts",
    "content": "import isSelectMultiple from \"./isSelectMultiple\";\n\ndescribe(\"isSelectMultiple\", () => {\n  it(\"should work correctly\", () => {\n    const select = document.createElement(\"select\");\n    expect(isSelectMultiple(select)).toBeFalsy();\n    select.multiple = true;\n    expect(isSelectMultiple(select)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isSelectMultiple.ts",
    "content": "import { FieldElement } from \"../types\";\n\nexport default (field: FieldElement): field is HTMLSelectElement =>\n  field.type === \"select-multiple\";\n"
  },
  {
    "path": "src/utils/isSelectOne.test.ts",
    "content": "import isSelectOne from \"./isSelectOne\";\n\ndescribe(\"isSelectOne\", () => {\n  it(\"should work correctly\", () => {\n    expect(isSelectOne(document.createElement(\"select\"))).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isSelectOne.ts",
    "content": "import { FieldElement } from \"../types\";\n\nexport default (field: FieldElement): field is HTMLSelectElement =>\n  field.type === \"select-one\";\n"
  },
  {
    "path": "src/utils/isUndefined.test.ts",
    "content": "import isUndefined from \"./isUndefined\";\n\ndescribe(\"isUndefined\", () => {\n  it(\"should work correctly\", () => {\n    expect(isUndefined(null)).toBeFalsy();\n    expect(isUndefined(NaN)).toBeFalsy();\n    expect(isUndefined(true)).toBeFalsy();\n    expect(isUndefined(1)).toBeFalsy();\n    expect(isUndefined(\"\")).toBeFalsy();\n    expect(isUndefined([])).toBeFalsy();\n    expect(isUndefined({})).toBeFalsy();\n    expect(isUndefined(new Date())).toBeFalsy();\n    expect(isUndefined(() => null)).toBeFalsy();\n    expect(isUndefined(undefined)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "src/utils/isUndefined.ts",
    "content": "export default (value: unknown): value is undefined => value === undefined;\n"
  },
  {
    "path": "src/utils/parseState.test.ts",
    "content": "import parseState from \"./parseState\";\n\ndescribe(\"parseState\", () => {\n  const state = {\n    values: { foo: \"🍎\" },\n    touched: { foo: true },\n    errors: { foo: \"🍎\" },\n    isDirty: false,\n    dirty: { foo: true },\n    isValidating: false,\n    isValid: true,\n    isSubmitting: false,\n    isSubmitted: false,\n    submitCount: 0,\n  };\n\n  it('should return value correctly when no \"path\" parameter', () => {\n    expect(parseState(undefined, state, undefined, undefined)).toBeUndefined();\n    expect(parseState(undefined, state, undefined, undefined, true)).toEqual(\n      state\n    );\n  });\n\n  it(\"should return value with correctly format\", () => {\n    const {\n      values: { foo: value },\n      errors: { foo: error },\n    } = state;\n    expect(parseState(\"foo\", state)).toBe(value);\n    expect(parseState([\"foo\", \"errors.foo\"], state)).toEqual([value, error]);\n    expect(parseState({ value: \"foo\", error: \"errors.foo\" }, state)).toEqual({\n      value,\n      error,\n    });\n  });\n\n  it(\"should call path handler correctly\", () => {\n    const handler = jest.fn();\n    const path = \"foo\";\n\n    parseState(path, state, handler);\n    expect(handler).toHaveBeenCalledWith(path);\n\n    parseState([path], state, handler);\n    expect(handler).toHaveBeenCalledWith(path);\n\n    parseState({ foo: path }, state, handler);\n    expect(handler).toHaveBeenCalledWith(path);\n  });\n\n  it(\"should call state handler correctly\", () => {\n    const handler = jest.fn();\n    const path = \"values.foo\";\n    const { foo } = state.values;\n\n    parseState(path, state, undefined, handler);\n    expect(handler).toHaveBeenCalledWith(path, foo);\n\n    parseState([path], state, undefined, handler);\n    expect(handler).toHaveBeenCalledWith(path, foo);\n\n    parseState({ foo: path }, state, undefined, handler);\n    expect(handler).toHaveBeenCalledWith(path, foo);\n  });\n});\n"
  },
  {
    "path": "src/utils/parseState.ts",
    "content": "import { FormState, ObjMap, Path } from \"../types\";\nimport get from \"./get\";\nimport getPath from \"./getPath\";\nimport isPlainObject from \"./isPlainObject\";\n\nexport default (\n  path: Path | undefined,\n  state: FormState,\n  pathHandler = getPath,\n  stateHandler?: (path: string, state: any) => any,\n  isGetState?: boolean\n): any => {\n  if (!path) return isGetState ? state : undefined;\n\n  let parsedState;\n\n  if (Array.isArray(path)) {\n    parsedState = path.map((p) => {\n      p = pathHandler(p);\n      const value = get(state, p);\n      return stateHandler ? stateHandler(p, value) : value;\n    });\n  } else if (isPlainObject(path)) {\n    const paths = path as ObjMap<string>;\n    parsedState = Object.keys(paths).reduce((s: ObjMap<any>, key) => {\n      path = pathHandler(paths[key]);\n      const value = get(state, path);\n      s[key] = stateHandler ? stateHandler(path, value) : value;\n      return s;\n    }, {});\n  } else {\n    path = pathHandler(path);\n    const value = get(state, path);\n    parsedState = stateHandler ? stateHandler(path, value) : value;\n  }\n\n  return parsedState;\n};\n"
  },
  {
    "path": "src/utils/runWithLowPriority.test.ts",
    "content": "import runWithLowPriority from \"./runWithLowPriority\";\n\njest.useFakeTimers();\n\ndescribe(\"runWithLowPriority\", () => {\n  it(\"should work correctly\", () => {\n    const fn = jest.fn();\n    runWithLowPriority(fn);\n    jest.runAllTimers();\n    expect(fn).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "src/utils/runWithLowPriority.ts",
    "content": "export default (callback: (args: any) => any): any =>\n  (\n    window.requestIdleCallback ||\n    ((cb) => {\n      const start = Date.now();\n      return setTimeout(\n        () =>\n          cb({\n            didTimeout: false,\n            timeRemaining: /* istanbul ignore next */ () =>\n              Math.max(0, 50 - (Date.now() - start)),\n          }),\n        1\n      );\n    })\n  )(callback, { timeout: 2000 });\n"
  },
  {
    "path": "src/utils/set.test.ts",
    "content": "import set from \"./set\";\n\ndescribe(\"set\", () => {\n  const other = { baz: \"🍋\" };\n\n  it(\"should throw error when input is invalid\", () => {\n    expect(() => set(null, \"foo\", \"🍎\")).toThrow(TypeError);\n    expect(() => set(undefined, \"foo\", \"🍎\")).toThrow(TypeError);\n    expect(() => set(NaN, \"foo\", \"🍎\")).toThrow(TypeError);\n    expect(() => set(true, \"foo\", \"🍎\")).toThrow(TypeError);\n    expect(() => set(\"\", \"foo\", \"🍎\")).toThrow(TypeError);\n    expect(() => set(1, \"foo\", \"🍎\")).toThrow(TypeError);\n    expect(() => set([], \"foo\", \"🍎\")).toThrow(TypeError);\n    expect(() => set(new Date(), \"foo\", \"🍎\")).toThrow(TypeError);\n    expect(() => set(() => null, \"foo\", \"🍎\")).toThrow(TypeError);\n  });\n\n  it(\"should set value by keys\", () => {\n    expect(set({ ...other }, \"foo\", \"🍎\")).toEqual({ foo: \"🍎\", ...other });\n    expect(set({ foo: \"\", ...other }, \"foo\", \"🍎\")).toEqual({\n      foo: \"🍎\",\n      ...other,\n    });\n    expect(set({ foo: {}, ...other }, \"foo\", \"🍎\")).toEqual({\n      foo: \"🍎\",\n      ...other,\n    });\n    expect(set({ foo: [], ...other }, \"foo\", \"🍎\")).toEqual({\n      foo: \"🍎\",\n      ...other,\n    });\n    expect(set({ foo: { a: \"\" }, ...other }, \"foo.a\", \"🍎\")).toEqual({\n      foo: { a: \"🍎\" },\n      ...other,\n    });\n    expect(set({ foo: { a: [] }, ...other }, \"foo.a.b\", \"🍎\")).toEqual({\n      foo: { a: { b: \"🍎\" } },\n      ...other,\n    });\n    expect(set({ foo: { a: { b: \"\" }, ...other } }, \"foo.a.b\", \"🍎\")).toEqual({\n      foo: { a: { b: \"🍎\" }, ...other },\n    });\n  });\n\n  it(\"should set value by indexes\", () => {\n    expect(set({ ...other }, \"foo.0\", \"🍎\")).toEqual({ foo: [\"🍎\"], ...other });\n    expect(set({ ...other }, \"foo.1\", \"🍎\")).toEqual({\n      foo: [, \"🍎\"],\n      ...other,\n    });\n    expect(set({ foo: [], ...other }, \"foo.0\", \"🍎\")).toEqual({\n      foo: [\"🍎\"],\n      ...other,\n    });\n    expect(set({ foo: {}, ...other }, \"foo.1\", \"🍎\")).toEqual({\n      foo: [, \"🍎\"],\n      ...other,\n    });\n    expect(set({ foo: {}, ...other }, \"foo.0.1\", \"🍎\")).toEqual({\n      foo: [[, \"🍎\"]],\n      ...other,\n    });\n    expect(set({ foo: {}, ...other }, \"foo.1.1\", \"🍎\")).toEqual({\n      foo: [, [, \"🍎\"]],\n      ...other,\n    });\n    expect(set({ foo: [\"🍋\"], ...other }, \"foo.1\", \"🍎\")).toEqual({\n      foo: [\"🍋\", \"🍎\"],\n      ...other,\n    });\n    expect(set({ foo: [\"🍋\"], ...other }, \"foo.2\", \"🍎\")).toEqual({\n      foo: [\"🍋\", , \"🍎\"],\n      ...other,\n    });\n\n    expect(set({ ...other }, \"foo[0]\", \"🍎\")).toEqual({\n      foo: [\"🍎\"],\n      ...other,\n    });\n    expect(set({ ...other }, \"foo[1]\", \"🍎\")).toEqual({\n      foo: [, \"🍎\"],\n      ...other,\n    });\n    expect(set({ foo: [], ...other }, \"foo[0]\", \"🍎\")).toEqual({\n      foo: [\"🍎\"],\n      ...other,\n    });\n    expect(set({ foo: {}, ...other }, \"foo[1]\", \"🍎\")).toEqual({\n      foo: [, \"🍎\"],\n      ...other,\n    });\n    expect(set({ foo: {}, ...other }, \"foo[0][1]\", \"🍎\")).toEqual({\n      foo: [[, \"🍎\"]],\n      ...other,\n    });\n    expect(set({ foo: {}, ...other }, \"foo[1][1]\", \"🍎\")).toEqual({\n      foo: [, [, \"🍎\"]],\n      ...other,\n    });\n    expect(set({ foo: [\"🍋\"], ...other }, \"foo[1]\", \"🍎\")).toEqual({\n      foo: [\"🍋\", \"🍎\"],\n      ...other,\n    });\n    expect(set({ foo: [\"🍋\"], ...other }, \"foo[2]\", \"🍎\")).toEqual({\n      foo: [\"🍋\", , \"🍎\"],\n      ...other,\n    });\n  });\n\n  it(\"should get value by mixed\", () => {\n    expect(\n      set({ foo: { a: [{ b: \"\" }] }, ...other }, \"foo.a[0].1\", \"🍎\")\n    ).toEqual({\n      foo: { a: [[, \"🍎\"]] },\n      ...other,\n    });\n    expect(\n      set({ foo: { a: [{ b: {} }] }, ...other }, \"foo.0.a[1]\", \"🍎\")\n    ).toEqual({\n      foo: [{ a: [, \"🍎\"] }],\n      ...other,\n    });\n    expect(\n      set({ foo: { a: [{ b: [], ...other }] } }, \"foo[0].a.b\", \"🍎\")\n    ).toEqual({\n      foo: [{ a: { b: \"🍎\" } }],\n    });\n    expect(\n      set({ foo: { a: [\"🍋\", { b: \"\" }], ...other } }, \"foo.a[1].b.0[1]\", \"🍎\")\n    ).toEqual({\n      foo: { a: [\"🍋\", { b: [[, \"🍎\"]] }], ...other },\n    });\n  });\n\n  it(\"should set value with mutable way\", () => {\n    const target = { foo: { a: \"🍋\" } };\n    set(target, \"foo.a\", \"🍎\");\n    expect(target).toEqual({ foo: { a: \"🍎\" } });\n  });\n\n  it(\"should set value with immutable way\", () => {\n    const target = { foo: { a: \"🍋\" } };\n    set(target, \"foo.a\", \"🍎\", true);\n    expect(target).toEqual({ foo: { a: \"🍋\" } });\n  });\n});\n"
  },
  {
    "path": "src/utils/set.ts",
    "content": "import cloneObject from \"./cloneObject\";\nimport isPlainObject from \"./isPlainObject\";\nimport stringToPath from \"./stringToPath\";\n\nexport default (\n  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n  object: any,\n  path: string,\n  value: unknown,\n  immutable?: boolean\n): any => {\n  if (!isPlainObject(object)) throw new TypeError(\"Expected an object.\");\n\n  const newObject = immutable ? cloneObject(object) : object;\n  const segs = stringToPath(path);\n\n  segs.slice(0, -1).reduce((obj, key, idx) => {\n    const nextIsNumber = !Number.isNaN(+segs[idx + 1]);\n    if (\n      (isPlainObject(obj[key]) && !nextIsNumber) ||\n      (Array.isArray(obj[key]) && nextIsNumber)\n    )\n      return obj[key];\n    obj[key] = nextIsNumber ? [] : {};\n    return obj[key];\n  }, newObject)[segs[segs.length - 1] || \"\"] = value;\n\n  return newObject;\n};\n"
  },
  {
    "path": "src/utils/setValuesAsTrue.test.ts",
    "content": "import setValuesAsTrue from \"./setValuesAsTrue\";\n\ndescribe(\"setValuesAsTrue\", () => {\n  it(\"should work correctly\", () => {\n    expect(setValuesAsTrue({})).toEqual({});\n    expect(setValuesAsTrue({ foo: {} })).toEqual({ foo: {} });\n    expect(setValuesAsTrue({ foo: [] })).toEqual({ foo: [] });\n    expect(setValuesAsTrue({ foo: true })).toEqual({ foo: true });\n    expect(setValuesAsTrue({ foo: undefined })).toEqual({ foo: true });\n    expect(setValuesAsTrue({ foo: null })).toEqual({ foo: true });\n    expect(setValuesAsTrue({ foo: NaN })).toEqual({ foo: true });\n    expect(setValuesAsTrue({ foo: 1 })).toEqual({ foo: true });\n    expect(setValuesAsTrue({ foo: \"\" })).toEqual({ foo: true });\n    expect(setValuesAsTrue({ foo: new Date() })).toEqual({ foo: true });\n    expect(setValuesAsTrue({ foo: () => null })).toEqual({ foo: true });\n    expect(setValuesAsTrue({ foo: [true] })).toEqual({ foo: [true] });\n    expect(setValuesAsTrue({ foo: [undefined] })).toEqual({ foo: [true] });\n    expect(setValuesAsTrue({ foo: [null] })).toEqual({ foo: [true] });\n    expect(setValuesAsTrue({ foo: [NaN] })).toEqual({ foo: [true] });\n    expect(setValuesAsTrue({ foo: [1] })).toEqual({ foo: [true] });\n    expect(setValuesAsTrue({ foo: [\"\"] })).toEqual({ foo: [true] });\n    expect(setValuesAsTrue({ foo: [new Date()] })).toEqual({ foo: [true] });\n    expect(setValuesAsTrue({ foo: [() => null] })).toEqual({ foo: [true] });\n    expect(setValuesAsTrue({ foo: { bar: [{ baz: false }, false] } })).toEqual({\n      foo: { bar: [{ baz: true }, true] },\n    });\n  });\n\n  it(\"should set value with immutable way\", () => {\n    const target = { foo: { a: \"🍎\" } };\n    setValuesAsTrue(target);\n    expect(target).toEqual({ foo: { a: \"🍎\" } });\n  });\n});\n"
  },
  {
    "path": "src/utils/setValuesAsTrue.ts",
    "content": "import isPlainObject from \"./isPlainObject\";\n\nconst setValuesAsTrue = (object: unknown): any => {\n  if (!Array.isArray(object) && !isPlainObject(object)) return true;\n\n  if (Array.isArray(object)) return object.map((val) => setValuesAsTrue(val));\n\n  return Object.keys(object).reduce((obj: Record<string, any>, key) => {\n    obj[key] = setValuesAsTrue((object as Record<string, any>)[key]);\n    return obj;\n  }, {});\n};\n\nexport default setValuesAsTrue;\n"
  },
  {
    "path": "src/utils/stringToPath.test.ts",
    "content": "import stringToPath from \"./stringToPath\";\n\ndescribe(\"stringToPath\", () => {\n  it(\"should throw error if input isn't a string\", () => {\n    // @ts-expect-error\n    expect(() => stringToPath([\"foo\", \"bar\"])).toThrow(TypeError);\n  });\n\n  it(\"should return empty array when input is empty string\", () => {\n    expect(stringToPath(\"\")).toEqual([]);\n  });\n\n  it(\"should split on dots\", () => {\n    expect(stringToPath(\"foo\")).toEqual([\"foo\"]);\n    expect(stringToPath(\"foo.bar\")).toEqual([\"foo\", \"bar\"]);\n    expect(stringToPath(\"foo.bar.baz\")).toEqual([\"foo\", \"bar\", \"baz\"]);\n\n    expect(stringToPath(\"0\")).toEqual([\"0\"]);\n    expect(stringToPath(\"0.1\")).toEqual([\"0\", \"1\"]);\n    expect(stringToPath(\"0.1.2\")).toEqual([\"0\", \"1\", \"2\"]);\n\n    expect(stringToPath(\"foo.0\")).toEqual([\"foo\", \"0\"]);\n    expect(stringToPath(\"foo.0.bar\")).toEqual([\"foo\", \"0\", \"bar\"]);\n    expect(stringToPath(\"foo.0.bar.1\")).toEqual([\"foo\", \"0\", \"bar\", \"1\"]);\n  });\n\n  it(\"should split on brackets\", () => {\n    expect(stringToPath(\"[0]\")).toEqual([\"0\"]);\n    expect(stringToPath(\"[0][1]\")).toEqual([\"0\", \"1\"]);\n    expect(stringToPath(\"[0][1][2]\")).toEqual([\"0\", \"1\", \"2\"]);\n  });\n\n  it(\"should split on mixed\", () => {\n    expect(stringToPath(\"foo[0]\")).toEqual([\"foo\", \"0\"]);\n    expect(stringToPath(\"foo[0].bar[1]\")).toEqual([\"foo\", \"0\", \"bar\", \"1\"]);\n    expect(stringToPath(\"foo[0][1][2].bar[4][5].baz[6]\")).toEqual([\n      \"foo\",\n      \"0\",\n      \"1\",\n      \"2\",\n      \"bar\",\n      \"4\",\n      \"5\",\n      \"baz\",\n      \"6\",\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/utils/stringToPath.ts",
    "content": "import compact from \"./compact\";\n\nexport default (str: string): string[] => {\n  if (typeof str !== \"string\") throw new TypeError(\"Expected a string.\");\n  if (!str.length) return [];\n\n  return compact(str.split(/[.[\\]]+/));\n};\n"
  },
  {
    "path": "src/utils/unset.test.ts",
    "content": "import unset from \"./unset\";\n\ndescribe(\"unset\", () => {\n  const other = { bar: \"🍋\" };\n\n  it(\"should throw error when input is invalid\", () => {\n    expect(() => unset(null, \"foo\")).toThrow(TypeError);\n    expect(() => unset(undefined, \"foo\")).toThrow(TypeError);\n    expect(() => unset(NaN, \"foo\")).toThrow(TypeError);\n    expect(() => unset(true, \"foo\")).toThrow(TypeError);\n    expect(() => unset(\"\", \"foo\")).toThrow(TypeError);\n    expect(() => unset(1, \"foo\")).toThrow(TypeError);\n    expect(() => unset([], \"foo\")).toThrow(TypeError);\n    expect(() => unset(new Date(), \"foo\")).toThrow(TypeError);\n    expect(() => unset(() => null, \"foo\")).toThrow(TypeError);\n  });\n\n  it(\"should do nothing if path is empty\", () => {\n    expect(unset({ foo: \"🍎\" }, \"\")).toEqual({ foo: \"🍎\" });\n  });\n\n  it(\"should unset value by keys\", () => {\n    expect(unset({ foo: undefined }, \"foo\")).toEqual({});\n    expect(unset(other, \"foo\")).toEqual(other);\n    expect(unset({ foo: {}, ...other }, \"foo\")).toEqual(other);\n    expect(unset({ foo: [], ...other }, \"foo\")).toEqual(other);\n    expect(unset({ foo: \"🍎\", ...other }, \"foo\")).toEqual(other);\n    expect(unset({ foo: { a: \"🍎\" }, ...other }, \"foo.a\")).toEqual(other);\n    expect(unset({ foo: { a: \"🍎\", b: \"🍋\" }, ...other }, \"foo.a\")).toEqual({\n      foo: { b: \"🍋\" },\n      ...other,\n    });\n    expect(\n      unset(\n        { foo: { a: \"🍎\", b: undefined, c: null, d: false, e: \"\" }, ...other },\n        \"foo.a\"\n      )\n    ).toEqual({\n      foo: { b: undefined, c: null, d: false, e: \"\" },\n      ...other,\n    });\n    expect(unset({ foo: { a: { b: \"🍎\", ...other } } }, \"foo.a.b\")).toEqual({\n      foo: { a: other },\n    });\n  });\n\n  it(\"should unset value by indexes\", () => {\n    expect(unset({ foo: [undefined] }, \"foo.0\")).toEqual({});\n    expect(unset(other, \"foo.0\")).toEqual(other);\n    expect(unset({ foo: {}, ...other }, \"foo.0\")).toEqual(other);\n    expect(unset({ foo: [], ...other }, \"foo.0\")).toEqual(other);\n    expect(unset({ foo: \"🍎\", ...other }, \"foo.0\")).toEqual({\n      foo: \"🍎\",\n      ...other,\n    });\n    expect(unset({ foo: [\"🍎\"], ...other }, \"foo.0\")).toEqual(other);\n    expect(unset({ foo: [\"🍎\", \"🍋\"], ...other }, \"foo.1\")).toEqual({\n      foo: [\"🍎\"],\n      ...other,\n    });\n    expect(unset({ foo: [\"🍎\", \"🍋\"], ...other }, \"foo.0\")).toEqual({\n      foo: [, \"🍋\"],\n      ...other,\n    });\n    expect(unset({ foo: [\"🍎\", undefined], ...other }, \"foo.0\")).toEqual(other);\n    expect(unset({ foo: [undefined, \"🍎\"], ...other }, \"foo.1\")).toEqual(other);\n    expect(\n      unset(\n        {\n          foo: [null, false, \"\", {}, [], undefined, \"🍎\"],\n          ...other,\n        },\n        \"foo.6\"\n      )\n    ).toEqual({\n      foo: [null, false, \"\", {}, []],\n      ...other,\n    });\n    expect(\n      unset(\n        {\n          foo: [null, false, \"\", {}, [], undefined, \"🍎\", \"🍋\"],\n          ...other,\n        },\n        \"foo.6\"\n      )\n    ).toEqual({\n      foo: [null, false, \"\", {}, [], undefined, , \"🍋\"],\n      ...other,\n    });\n    expect(unset({ foo: [[\"🍎\"]], ...other }, \"foo.0.0\")).toEqual(other);\n    expect(unset({ foo: [[\"🍎\"], [\"🍋\"]], ...other }, \"foo.1.0\")).toEqual({\n      foo: [[\"🍎\"]],\n      ...other,\n    });\n    expect(unset({ foo: [[\"🍋\", \"🍎\"], [\"🥝\"]], ...other }, \"foo.0.1\")).toEqual(\n      {\n        foo: [[\"🍋\"], [\"🥝\"]],\n        ...other,\n      }\n    );\n\n    expect(unset({ foo: [undefined] }, \"foo[0]\")).toEqual({});\n    expect(unset(other, \"foo[0]\")).toEqual(other);\n    expect(unset({ foo: {}, ...other }, \"foo[0]\")).toEqual(other);\n    expect(unset({ foo: [], ...other }, \"foo[0]\")).toEqual(other);\n    expect(unset({ foo: \"🍎\", ...other }, \"foo[0]\")).toEqual({\n      foo: \"🍎\",\n      ...other,\n    });\n    expect(unset({ foo: [\"🍎\"], ...other }, \"foo[0]\")).toEqual(other);\n    expect(unset({ foo: [\"🍎\", \"🍋\"], ...other }, \"foo[1]\")).toEqual({\n      foo: [\"🍎\"],\n      ...other,\n    });\n    expect(unset({ foo: [\"🍎\", \"🍋\"], ...other }, \"foo[0]\")).toEqual({\n      foo: [, \"🍋\"],\n      ...other,\n    });\n    expect(unset({ foo: [\"🍎\", undefined], ...other }, \"foo[0]\")).toEqual(\n      other\n    );\n    expect(unset({ foo: [undefined, \"🍎\"], ...other }, \"foo[1]\")).toEqual(\n      other\n    );\n    expect(\n      unset(\n        {\n          foo: [null, false, \"\", {}, [], undefined, \"🍎\"],\n          ...other,\n        },\n        \"foo[6]\"\n      )\n    ).toEqual({\n      foo: [null, false, \"\", {}, []],\n      ...other,\n    });\n    expect(\n      unset(\n        {\n          foo: [null, false, \"\", {}, [], undefined, \"🍎\", \"🍋\"],\n          ...other,\n        },\n        \"foo[6]\"\n      )\n    ).toEqual({\n      foo: [null, false, \"\", {}, [], undefined, , \"🍋\"],\n      ...other,\n    });\n    expect(unset({ foo: [[\"🍎\"]], ...other }, \"foo[0][0]\")).toEqual(other);\n    expect(unset({ foo: [[\"🍎\"], [\"🍋\"]], ...other }, \"foo[1][0]\")).toEqual({\n      foo: [[\"🍎\"]],\n      ...other,\n    });\n    expect(\n      unset({ foo: [[\"🍋\", \"🍎\"], [\"🥝\"]], ...other }, \"foo[0][1]\")\n    ).toEqual({\n      foo: [[\"🍋\"], [\"🥝\"]],\n      ...other,\n    });\n  });\n\n  it(\"should unset value by mixed\", () => {\n    expect(\n      unset(\n        { foo: [{ a: [{ b: [undefined, { c: \"🍎\" }] }] }] },\n        \"foo.0.a[0].b.1.c\"\n      )\n    ).toEqual({});\n    expect(\n      unset({ foo: { a: { b: [\"🍋\", [\"🥝\", \"🍎\"]] } } }, \"foo.a.b.1[0]\")\n    ).toEqual({ foo: { a: { b: [\"🍋\", [, \"🍎\"]] } } });\n    expect(\n      unset(\n        {\n          foo: [\n            { a: [\"🍋\", false, {}, [], undefined, \"🍎\", null, \"\"], ...other },\n          ],\n        },\n        \"foo[0].a.5\"\n      )\n    ).toEqual({\n      foo: [{ a: [\"🍋\", false, {}, [], undefined, , null, \"\"], ...other }],\n    });\n    expect(\n      unset(\n        { foo: { a: [\"🍋\", { b: [{ c: \"🍎\" }, { d: \"🥝\" }] }] }, ...other },\n        \"foo.a.1.b[0].c\"\n      )\n    ).toEqual({ foo: { a: [\"🍋\", { b: [, { d: \"🥝\" }] }] }, ...other });\n    expect(\n      unset(\n        { foo: [\"🍋\", { a: [\"🥝\", [[{ b: \"🍎\" }, undefined]]], ...other }] },\n        \"foo.1.a[1].0[0].b\"\n      )\n    ).toEqual({ foo: [\"🍋\", { a: [\"🥝\"], ...other }] });\n    expect(\n      unset(\n        { foo: [{ a: [{ b: [{ c: [undefined, \"🍎\"] }] }] }] },\n        \"foo[0].a.0.b[0].c.1\"\n      )\n    ).toEqual({});\n    expect(\n      unset(\n        {\n          foo: [{ a: [{ b: [{ c: [undefined, \"🍎\"] }] }], ...other }],\n        },\n        \"foo[0].a.0.b[0].c.1\"\n      )\n    ).toEqual({ foo: [other] });\n  });\n\n  it(\"should unset value with mutable way\", () => {\n    const target = { foo: { a: { b: \"🍋\" } } };\n    unset(target, \"foo.a\");\n    expect(target).toEqual({});\n  });\n\n  it(\"should unset value with immutable way\", () => {\n    const target = { foo: { a: { b: \"🍋\" } } };\n    unset(target, \"foo.a\", true);\n    expect(target).toEqual({ foo: { a: { b: \"🍋\" } } });\n  });\n});\n"
  },
  {
    "path": "src/utils/unset.ts",
    "content": "import cloneObject from \"./cloneObject\";\nimport isEmptyObject from \"./isEmptyObject\";\nimport isPlainObject from \"./isPlainObject\";\nimport isUndefined from \"./isUndefined\";\nimport stringToPath from \"./stringToPath\";\n\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nconst unset = (object: any, path: string, immutable?: boolean): any => {\n  if (!isPlainObject(object)) throw new TypeError(\"Expected an object.\");\n\n  const refObject = immutable ? cloneObject(object) : object;\n  const newObject = refObject;\n\n  // eslint-disable-next-line no-prototype-builtins\n  if (newObject.hasOwnProperty(path)) {\n    delete newObject[path];\n    return refObject;\n  }\n\n  const segs = stringToPath(path);\n\n  if (!segs.length) return refObject;\n\n  const last = segs.pop() as string;\n  const target = segs.reduce((obj, key) => (obj || {})[key], newObject);\n\n  if (Array.isArray(target)) {\n    let index = +last;\n\n    if (index < target.length - 1) {\n      delete target[index];\n    } else {\n      while (index >= 0) {\n        // @ts-expect-error\n        if (index == last || isUndefined(target[index])) {\n          target.splice(index, 1);\n          index -= 1;\n        } else {\n          break;\n        }\n      }\n    }\n  } else if (isPlainObject(target)) {\n    delete target[last];\n  }\n\n  return isEmptyObject(target) ||\n    (Array.isArray(target) && !target.filter((t) => !isUndefined(t)).length)\n    ? unset(refObject, segs.join(\".\"))\n    : refObject;\n};\n\nexport default unset;\n"
  },
  {
    "path": "src/utils/warn.test.ts",
    "content": "import warn from \"./warn\";\n\ndescribe(\"warn\", () => {\n  it(\"should work correctly\", () => {\n    console.warn = jest.fn();\n    warn(\"🍎\", \"🍋\");\n    expect(console.warn).toHaveBeenCalledWith(\"🍎\", \"🍋\");\n\n    console.warn = jest.fn();\n    // @ts-expect-error\n    global.__DEV__ = false;\n    warn(\"🍎\", \"🍋\");\n    expect(console.warn).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "src/utils/warn.ts",
    "content": "export default (...args: any[]): void => {\n  if (__DEV__) console.warn(...args);\n};\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"target\": \"ESNext\",\n    \"module\": \"ESNext\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"jsx\": \"react-jsx\",\n    // Specify module resolution strategy: \"node\" (Node.js) or \"classic\" (TypeScript pre-1.6)\n    \"moduleResolution\": \"node\",\n    // Ensure that Babel can safely transpile files in the TypeScript project\n    \"isolatedModules\": true,\n    // Enable all strict type-checking options. Recommended by TS\n    \"strict\": true,\n    // Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports.\n    // Implies \"allowSyntheticDefaultImports\". Recommended by TS\n    \"esModuleInterop\": true,\n    // Disallow inconsistently-cased references to the same file. Recommended by TS\n    \"forceConsistentCasingInFileNames\": true,\n    // Do not emit outputs\n    \"noEmit\": true,\n    // Raise error on expressions and declarations with an implied \"any\" type\n    \"noImplicitAny\": true,\n    // Report errors on unused locals\n    \"noUnusedLocals\": true,\n    // Report errors on unused parameters\n    \"noUnusedParameters\": true,\n    // Report error when not all code paths in function return a value\n    \"noImplicitReturns\": true,\n    // Report errors for fallthrough cases in switch statement\n    \"noFallthroughCasesInSwitch\": true\n  },\n  \"include\": [\"src\", \"scripts/jest/setup.ts\"]\n}\n"
  },
  {
    "path": "website/.gitignore",
    "content": "# Dependencies\nnode_modules\n\n# Production\nbuild\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "website/.prettierignore",
    "content": "# Production\nbuild\n\n# Misc\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "website/README.md",
    "content": "# Website\n\nThis website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator.\n\n## Installation\n\n```console\nyarn install\n```\n\n## Local Development\n\n```console\nyarn start\n```\n\nThis command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server.\n\n## Build\n\n```console\nyarn build\n```\n\nThis command generates static content into the `build` directory and can be served using any static contents hosting service.\n\n## Deployment\n\n```console\nGIT_USER=<Your GitHub username> USE_SSH=true yarn deploy\n```\n\nIf you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.\n"
  },
  {
    "path": "website/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve(\"@docusaurus/core/lib/babel/preset\")],\n};\n"
  },
  {
    "path": "website/docusaurus.config.js",
    "content": "const github = \"https://github.com/wellyshen/react-cool-form\";\n\nmodule.exports = {\n  title: \"React Cool Form\",\n  url: \"https://react-cool-form.netlify.app\",\n  baseUrl: \"/\",\n  onBrokenLinks: \"throw\",\n  onBrokenMarkdownLinks: \"warn\",\n  favicon: \"img/favicon.ico\",\n  customFields: {\n    description:\n      \"React hooks for forms state and validation, less code more performant.\",\n    keywords: [\n      \"React\",\n      \"Hooks\",\n      \"React-hooks\",\n      \"Forms\",\n      \"Form\",\n      \"Form-builder\",\n      \"Form-validation\",\n      \"Form-state\",\n      \"Validation\",\n      \"State\",\n      \"State-management\",\n      \"DX\",\n      \"UX\",\n      \"Performance\",\n      \"Controlled\",\n      \"Uncontrolled\",\n      \"Asynchronous\",\n      \"Typescript\",\n    ],\n  },\n  organizationName: \"wellyshen\",\n  projectName: \"react-cool-form\",\n  themeConfig: {\n    image: \"img/react-cool-form.png\",\n    colorMode: { defaultMode: \"dark\" },\n    announcementBar: {\n      id: \"start_us\",\n      content: `Hi! friends, if this library has helped you out, please support us with a ⭐️ on <a href=${github} target=\"_blank\" rel=\"noopener noreferrer\">GitHub</a>`,\n      textColor: \"#fff\",\n      backgroundColor: \"#1c7ef7\",\n    },\n    algolia: {\n      apiKey: \"0afb2d2ec7187233d3642b33908d1bf1\",\n      indexName: \"react-cool-form\",\n      contextualSearch: true,\n    },\n    googleAnalytics: {\n      trackingID: \"UA-186962415-1\",\n      anonymizeIP: true,\n    },\n    navbar: {\n      title: \"React Cool Form\",\n      logo: {\n        alt: \"React Cool Form\",\n        src: \"img/logo.svg\",\n      },\n      items: [\n        {\n          to: \"/docs\",\n          label: \"Docs\",\n          position: \"right\",\n        },\n        {\n          to: \"/docs/examples/basic\",\n          label: \"Examples\",\n          position: \"right\",\n        },\n        {\n          to: \"/docs/api-reference/use-form\",\n          label: \"API\",\n          position: \"right\",\n        },\n        {\n          href: github,\n          label: \"GitHub\",\n          position: \"right\",\n        },\n      ],\n    },\n    footer: {\n      style: \"dark\",\n      links: [\n        {\n          title: \"Docs\",\n          items: [\n            {\n              label: \"Getting Started\",\n              to: \"/docs\",\n            },\n            {\n              label: \"Examples\",\n              to: \"/docs/examples/basic\",\n            },\n            {\n              label: \"API Reference\",\n              to: \"/docs/api-reference/use-form\",\n            },\n          ],\n        },\n        {\n          title: \"Community\",\n          items: [\n            {\n              label: \"Stack Overflow\",\n              href:\n                \"https://stackoverflow.com/questions/tagged/react-cool-form\",\n            },\n            {\n              label: \"Contributor Covenant\",\n              href:\n                \"https://www.contributor-covenant.org/version/2/0/code_of_conduct\",\n            },\n          ],\n        },\n        {\n          title: \"More\",\n          items: [\n            { label: \"GitHub\", href: github },\n            {\n              html: `\n                <a href=\"https://www.netlify.com\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Deploys by Netlify\">\n                  <img src=\"https://www.netlify.com/img/global/badges/netlify-color-accent.svg\" alt=\"Deploys by Netlify\" />\n                </a>\n              `,\n            },\n          ],\n        },\n      ],\n      copyright: `Copyright © ${new Date().getFullYear()} Welly Shen.`,\n    },\n  },\n  presets: [\n    [\n      \"@docusaurus/preset-classic\",\n      {\n        docs: {\n          path: \"../docs\",\n          sidebarPath: require.resolve(\"./sidebars.js\"),\n          editUrl: `${github}/edit/master/website`,\n          remarkPlugins: [\n            [require(\"@docusaurus/remark-plugin-npm2yarn\"), { sync: true }],\n          ],\n        },\n        theme: {\n          customCss: require.resolve(\"./src/css/custom.scss\"),\n        },\n      },\n    ],\n  ],\n  plugins: [\"docusaurus-plugin-sass\"],\n};\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"name\": \"docs\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"start\": \"docusaurus start\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"serve\": \"docusaurus serve\",\n    \"clear\": \"docusaurus clear\",\n    \"lint\": \"prettier -w . -u --loglevel silent\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"^2.0.0-beta.3\",\n    \"@docusaurus/preset-classic\": \"^2.0.0-beta.3\",\n    \"@docusaurus/remark-plugin-npm2yarn\": \"^2.0.0-beta.3\",\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"clsx\": \"^1.1.1\",\n    \"docusaurus-plugin-sass\": \"^0.2.1\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.5%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"devDependencies\": {\n    \"prettier\": \"^2.3.2\",\n    \"sass\": \"^1.36.0\"\n  }\n}\n"
  },
  {
    "path": "website/sidebars.js",
    "content": "module.exports = {\n  docs: {\n    \"Getting Started\": [\n      \"getting-started/getting-started\",\n      \"getting-started/typescript-support\",\n      \"getting-started/integration-an-existing-form\",\n      \"getting-started/validation-guide\",\n      \"getting-started/form-submission\",\n      \"getting-started/reset-form\",\n      \"getting-started/form-state\",\n      \"getting-started/complex-structures\",\n      \"getting-started/arrays-and-lists\",\n      \"getting-started/3rd-party-ui-libraries\",\n      \"getting-started/bundle-size-overview\",\n      \"getting-started/accessibility\",\n    ],\n    Examples: [\n      \"examples/basic\",\n      \"examples/built-in-validation\",\n      \"examples/form-level-validation\",\n      \"examples/field-level-validation\",\n      \"examples/validation-with-schema\",\n      \"examples/form-submission\",\n      \"examples/reset-form\",\n      \"examples/checkboxes\",\n      \"examples/radio-group\",\n      \"examples/multi-select\",\n      \"examples/complex-structures\",\n      \"examples/arrays-and-lists\",\n      \"examples/conditional-fields\",\n      \"examples/lazy-default-values\",\n      \"examples/material-ui\",\n      \"examples/react-select\",\n      \"examples/custom-field\",\n      \"examples/isolating-rerendering\",\n      \"examples/wizard-form\",\n      \"examples/without-form-element\",\n      \"examples/virtualized-lists\",\n    ],\n    \"API Reference\": [\n      \"api-reference/use-form\",\n      \"api-reference/use-form-methods\",\n      \"api-reference/use-form-state\",\n      \"api-reference/use-controlled\",\n      \"api-reference/use-field-array\",\n      \"api-reference/utility-functions\",\n    ],\n  },\n};\n"
  },
  {
    "path": "website/src/css/custom.scss",
    "content": "/* stylelint-disable docusaurus/copyright-header */\n/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n:root {\n  --ifm-color-primary: #0971f1;\n  --ifm-color-primary-dark: #0866d9;\n  --ifm-color-primary-darker: #0860cd;\n  --ifm-color-primary-darkest: #064fa9;\n  --ifm-color-primary-light: #1c7ef7;\n  --ifm-color-primary-lighter: #2985f7;\n  --ifm-color-primary-lightest: #4d9af8;\n  --ifm-code-font-size: 95%;\n}\n\n.docusaurus-highlight-code-line {\n  background-color: rgb(72, 77, 91);\n  display: block;\n  margin: 0 calc(-1 * var(--ifm-pre-padding));\n  padding: 0 var(--ifm-pre-padding);\n}\n"
  },
  {
    "path": "website/src/pages/index.js",
    "content": "import React from \"react\";\nimport clsx from \"clsx\";\nimport Layout from \"@theme/Layout\";\nimport Link from \"@docusaurus/Link\";\nimport useDocusaurusContext from \"@docusaurus/useDocusaurusContext\";\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\n\nimport styles from \"./styles.module.scss\";\n\nconst features = [\n  {\n    title: \"Easy to Use\",\n    imageUrl: \"img/form.svg\",\n    description: (\n      <>\n        React Cool Form is{\" \"}\n        <Link to=\"/docs/api-reference/use-form\">\ba set of React hooks</Link> that\n        helps you conquer all kinds of forms. See how easy to{\" \"}\n        <Link to=\"/docs/getting-started/integration-an-existing-form\">\n          integrate it with your form\n        </Link>\n        .\n      </>\n    ),\n  },\n  {\n    title: \"Manage Complex Data\",\n    imageUrl: \"img/layout.svg\",\n    description: (\n      <>\n        Struggling with form structures? With React Cool Form{\" \"}\n        <Link to=\"/docs/getting-started/complex-structures\">\bnested fields</Link>{\" \"}\n        API, you can create complex form structures without hassle.\n      </>\n    ),\n  },\n  {\n    title: \"Validate by Your Favor\",\n    imageUrl: \"img/checklist.svg\",\n    description: (\n      <>\n        Supports{\" \"}\n        <Link to=\"/docs/getting-started/validation-guide#built-in-validation\">\n          \bbuilt-in\n        </Link>\n        ,{\" \"}\n        <Link to=\"/docs/getting-started/validation-guide#form-level-validation\">\n          form-level\n        </Link>\n        , and{\" \"}\n        <Link to=\"/docs/getting-started/validation-guide#field-level-validation\">\n          \bfield-level\n        </Link>{\" \"}\n        validation, which can cover all the cases that you need.\n      </>\n    ),\n  },\n  {\n    title: \"Highly Performant\",\n    imageUrl: \"img/superhero.svg\",\n    description: (\n      <>\n        <Link to=\"#performance-matters\">\n          Minimizes the number of re-renders\n        </Link>{\" \"}\n        for you. Building forms with great user experience can be a natural\n        thing.\n      </>\n    ),\n  },\n  {\n    title: \"Developer Experience\",\n    imageUrl: \"img/coding.svg\",\n    description: (\n      <>\n        Intuitive and flexible{\" \"}\n        <Link to=\"/docs/api-reference/use-form\">APIs</Link> design, provides a\n        seamless way to integration with existing HTML form inputs or{\" \"}\n        <Link to=\"/docs/getting-started/3rd-party-ui-libraries\">\n          3rd-party UI libraries\n        </Link>\n        .\n      </>\n    ),\n  },\n  {\n    title: \"Super Lightweight\",\n    imageUrl: \"img/loading.svg\",\n    description: (\n      <>\n        The lower size the faster speed. React Cool Form is a{\" \"}\n        <Link to=\"/docs/getting-started/bundle-size-overview\">tiny size</Link>{\" \"}\n        library but powerful.\n      </>\n    ),\n  },\n];\n\nfunction Feature({ imageUrl, title, description }) {\n  const imgUrl = useBaseUrl(imageUrl);\n  return (\n    <div className={clsx(\"col col--4\", styles.feature)}>\n      {imgUrl && (\n        <div className=\"text--center\">\n          <img className={styles.featureImage} src={imgUrl} alt={title} />\n        </div>\n      )}\n      <h3>{title}</h3>\n      <p>{description}</p>\n    </div>\n  );\n}\n\nfunction Home() {\n  const context = useDocusaurusContext();\n  const { description, keywords } = context.siteConfig.customFields;\n  return (\n    <Layout description={description} keywords={keywords}>\n      <header className={clsx(\"hero\", styles.heroBanner)}>\n        <div className=\"container\">\n          <img src=\"/img/logo.svg\" alt=\"React Cool Form\" />\n          <div>\n            <h1 className={clsx(\"hero__title\", styles.heroTitle)}>\n              React hooks for forms <b>state</b> and <b>validation</b>, less\n              code more <b>performant</b>\n            </h1>\n            <div className={styles.buttons}>\n              <Link\n                className={clsx(\"button button--lg\", styles.getStarted)}\n                to={useBaseUrl(\"docs/\")}\n              >\n                Get Started\n              </Link>\n              <span className={styles.gitHubBtnWrapper}>\n                <iframe\n                  className={styles.gitHubBtn}\n                  src=\"https://ghbtns.com/github-btn.html?user=wellyshen&repo=react-cool-form&type=star&count=true&size=large\"\n                  width={160}\n                  height={30}\n                  title=\"GitHub Stars\"\n                />\n              </span>\n            </div>\n          </div>\n        </div>\n      </header>\n      <main>\n        {features.length && (\n          <section className={styles.features}>\n            <div className=\"container\">\n              <div className=\"row\">\n                {features.map((props, idx) => (\n                  <Feature key={idx} {...props} />\n                ))}\n              </div>\n            </div>\n          </section>\n        )}\n        <section className={styles.showbox}>\n          <h2 id=\"performance-matters\">Performance Matters</h2>\n          <p>\n            Building forms in React can be simple and performant. React Cool\n            Form eliminates unnecessary re-renders throughout the development\n            process. Now dive into the following example to learn more.\n          </p>\n          <iframe\n            className={styles.iframe}\n            src=\"https://codesandbox.io/embed/rcf-showbox-8b0qn?fontsize=14&hidenavigation=1&theme=dark\"\n            title=\"RCF - Showbox\"\n            allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n            sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n          />\n        </section>\n      </main>\n    </Layout>\n  );\n}\n\nexport default Home;\n"
  },
  {
    "path": "website/src/pages/styles.module.scss",
    "content": "/* stylelint-disable docusaurus/copyright-header */\n\n/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  padding: 3rem;\n  background: #2b3137;\n\n  > div {\n    display: flex;\n    flex-direction: row-reverse;\n  }\n\n  img {\n    margin-left: 2.5rem;\n    min-width: 240px;\n  }\n\n  .heroTitle {\n    margin-bottom: 2rem;\n    font-size: 3.75rem;\n    color: #fff;\n\n    & b {\n      color: var(--ifm-color-primary);\n    }\n  }\n\n  .buttons {\n    display: flex;\n    align-items: center;\n  }\n\n  .getStarted {\n    padding: 1rem 2rem;\n    border: none;\n    background: var(--ifm-color-primary);\n    text-transform: uppercase;\n    font-size: 1.5rem;\n    color: #fff;\n\n    &:hover {\n      background: var(--ifm-color-primary-dark);\n    }\n  }\n\n  .gitHubBtnWrapper {\n    display: flex;\n\n    .gitHubBtn {\n      margin-left: 24px;\n      border: none;\n    }\n  }\n}\n\n.features {\n  display: flex;\n  align-items: center;\n  padding: 2rem 0;\n  width: 100%;\n\n  .feature {\n    text-align: center;\n  }\n\n  .featureImage {\n    height: 200px;\n    width: 200px;\n  }\n}\n\n.showbox {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  padding-bottom: 4.5rem;\n  text-align: center;\n  background: var(--ifm-color-emphasis-100);\n\n  h2 {\n    padding-top: 4.5rem;\n  }\n\n  p {\n    width: 50%;\n  }\n\n  .iframe {\n    width: 80%;\n    height: 500px;\n    border: 0;\n    border-radius: 4px;\n    overflow: hidden;\n  }\n}\n\n@media only screen and (max-width: 768px) {\n  .heroBanner {\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n    text-align: center;\n\n    > div {\n      display: block;\n    }\n\n    img {\n      display: block;\n      width: 220px;\n      margin: 0 auto 2.5rem;\n    }\n\n    .heroTitle {\n      font-size: 2.5rem;\n    }\n\n    .buttons {\n      justify-content: center;\n    }\n\n    .gitHubBtnWrapper {\n      display: none;\n    }\n  }\n}\n\n@media screen and (max-width: 966px) {\n  .showbox {\n    p {\n      width: 90%;\n    }\n\n    .iframe {\n      width: 100%;\n    }\n  }\n}\n"
  },
  {
    "path": "website/static/.nojekyll",
    "content": ""
  }
]