├── .eslintrc.js
├── .github
├── CONTRIBUTING.md
├── stale.yml
└── workflows
│ ├── compare-src.yml
│ ├── lock-issue.yml
│ ├── sync-src-excluded-translate.yml
│ └── sync-upstream.yml
├── .gitignore
├── .husky
└── pre-commit
├── .prettierrc
├── .vscode
└── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── contentlayer.config.ts
├── next-env.d.ts
├── next.config.mjs
├── origin-src
├── components
│ ├── Admonition.module.css
│ ├── Admonition.tsx
│ ├── ApiFormState.tsx
│ ├── ApiGallery.module.css
│ ├── ApiGallery.tsx
│ ├── ApiPage.module.css
│ ├── Bday.module.css
│ ├── BeekaiBuilderPage.module.css
│ ├── BeekaiBuilderPage.tsx
│ ├── BuilderPage.module.css
│ ├── BuilderPage.tsx
│ ├── ClipBoard.tsx
│ ├── CodeArea.module.css
│ ├── CodeArea.tsx
│ ├── CodeCompareSection.module.css
│ ├── CodeCompareSection.tsx
│ ├── CodePerfCompareSection.module.css
│ ├── CodePerfCompareSection.tsx
│ ├── CodeSandbox.tsx
│ ├── DevToolFeaturesList.module.css
│ ├── DevToolFeaturesList.tsx
│ ├── DevTools.module.css
│ ├── DevTools.tsx
│ ├── FeatureList.module.css
│ ├── FeaturesList.tsx
│ ├── Footer.module.css
│ ├── Footer.tsx
│ ├── Form.module.css
│ ├── Form.tsx
│ ├── FormFields.module.css
│ ├── FormFields.tsx
│ ├── FormStateApi.tsx
│ ├── FormStateTable.tsx
│ ├── GetStarted.module.css
│ ├── Header.module.css
│ ├── Header.tsx
│ ├── HomePage.module.css
│ ├── HomePage.tsx
│ ├── IsolateRender.module.css
│ ├── IsolateRender.tsx
│ ├── Menu
│ │ ├── Menu.tsx
│ │ ├── MenuLinks.ts
│ │ ├── SideMenu.module.css
│ │ └── index.ts
│ ├── Nav.module.css
│ ├── Nav.tsx
│ ├── Popup.module.css
│ ├── Popup.tsx
│ ├── ResourceList.tsx
│ ├── ResourcePage.module.css
│ ├── ResourcePageArticles.tsx
│ ├── ResourcePageBindings.tsx
│ ├── ResourcePageNewsletter.tsx
│ ├── ResourcePageVideos.tsx
│ ├── Search.module.css
│ ├── Search.tsx
│ ├── SortableContainer.module.css
│ ├── SortableContainer.tsx
│ ├── StarRepo.tsx
│ ├── TabGroup.module.css
│ ├── TabGroup.tsx
│ ├── Toggle.module.css
│ ├── Toggle.tsx
│ ├── TypeText.tsx
│ ├── UseController.tsx
│ ├── UseControllerContent.tsx
│ ├── UseControllerMethods.tsx
│ ├── UseFieldArray.tsx
│ ├── UseFieldArrayContent.tsx
│ ├── Watcher.module.css
│ ├── Watcher.tsx
│ ├── codeExamples
│ │ ├── dependantFieldsTS.tsx
│ │ ├── devTool.tsx
│ │ ├── formState.ts
│ │ ├── formStateTs.ts
│ │ ├── formStateUseEffect.ts
│ │ ├── formStateUseEffectTs.ts
│ │ ├── reactHookFormCode.ts
│ │ ├── useController.ts
│ │ ├── useControllerCheckboxes.ts
│ │ ├── useControllerTs.ts
│ │ ├── useFieldArray.ts
│ │ ├── useFieldArrayArgument.ts
│ │ ├── useFieldArrayConditional.ts
│ │ ├── useFieldArrayFocus.ts
│ │ ├── useFieldArrayPreview.ts
│ │ ├── useFieldArrayTS.ts
│ │ └── useFormState.ts
│ ├── general-observer.tsx
│ ├── layout.css
│ ├── layout.tsx
│ ├── learnMore.tsx
│ ├── logic
│ │ ├── generateCode.ts
│ │ └── getEditLink.tsx
│ ├── mdx
│ │ ├── code.tsx
│ │ ├── mdx.tsx
│ │ ├── pre.tsx
│ │ ├── theme.ts
│ │ └── youtube.tsx
│ ├── selectNav.module.css
│ ├── selectNav.tsx
│ ├── seo.tsx
│ ├── sponsorsList.module.css
│ ├── sponsorsList.tsx
│ └── utils
│ │ ├── copyClipBoard.ts
│ │ ├── goToBuilder.ts
│ │ └── useWindowSize.ts
├── content
│ ├── advanced-usage.mdx
│ ├── docs
│ │ ├── createFormControl.mdx
│ │ ├── formprovider.mdx
│ │ ├── usecontroller
│ │ │ └── controller.mdx
│ │ ├── useform.mdx
│ │ ├── useform
│ │ │ ├── clearerrors.mdx
│ │ │ ├── control.mdx
│ │ │ ├── form.mdx
│ │ │ ├── formstate.mdx
│ │ │ ├── getfieldstate.mdx
│ │ │ ├── getvalues.mdx
│ │ │ ├── handlesubmit.mdx
│ │ │ ├── register.mdx
│ │ │ ├── reset.mdx
│ │ │ ├── resetfield.mdx
│ │ │ ├── seterror.mdx
│ │ │ ├── setfocus.mdx
│ │ │ ├── setvalue.mdx
│ │ │ ├── trigger.mdx
│ │ │ ├── unregister.mdx
│ │ │ └── watch.mdx
│ │ ├── useformcontext.mdx
│ │ ├── useformstate.mdx
│ │ ├── useformstate
│ │ │ └── errormessage.mdx
│ │ └── usewatch.mdx
│ ├── faqs.mdx
│ ├── get-started.mdx
│ └── ts.mdx
├── data
│ ├── api.tsx
│ ├── builder.tsx
│ ├── devtools.tsx
│ ├── generic.tsx
│ ├── home.tsx
│ ├── nav.tsx
│ └── resources.tsx
├── pages
│ ├── 404.module.css
│ ├── 404.tsx
│ ├── [...slug].tsx
│ ├── _app.tsx
│ ├── _document.tsx
│ ├── about-us.tsx
│ ├── dev-tools.tsx
│ ├── docs.tsx
│ ├── docs
│ │ ├── usecontroller.tsx
│ │ └── usefieldarray.tsx
│ ├── form-builder.tsx
│ ├── index.tsx
│ ├── media.module.css
│ ├── media.tsx
│ ├── migrate-v6-to-v7.tsx
│ └── resources
│ │ ├── 3rd-party-bindings.tsx
│ │ ├── articles.tsx
│ │ ├── newsletters.tsx
│ │ └── videos.tsx
├── state
│ └── formData.ts
├── styles
│ ├── breakpoints.ts
│ ├── button.module.css
│ ├── colors.ts
│ ├── container.module.css
│ ├── table.module.css
│ └── typography.module.css
└── types
│ ├── global.d.ts
│ ├── little-state-machine.d.ts
│ └── types.ts
├── package.json
├── pnpm-lock.yaml
├── public
├── images
│ ├── Logo.svg
│ ├── casinoreviews.png
│ ├── dev-tool.png
│ ├── formik.min.png
│ ├── gatsby-icon.png
│ ├── hookForm.png
│ ├── hookform.min.png
│ ├── logo
│ │ ├── react-hook-form-logo-grey.png
│ │ ├── react-hook-form-logo-grey.svg
│ │ ├── react-hook-form-logo-only-grey.png
│ │ ├── react-hook-form-logo-only-grey.svg
│ │ ├── react-hook-form-logo-only.png
│ │ ├── react-hook-form-logo-only.svg
│ │ ├── react-hook-form-logo.png
│ │ └── react-hook-form-logo.svg
│ ├── open-link.svg
│ ├── react-hook-form-og.png
│ ├── reduxform.min.png
│ └── route4me.png
└── video
│ ├── react-hook-form-demo-video.mp4
│ └── react-hook-form-native-demo-video.mp4
├── src
├── components
│ ├── Admonition.module.css
│ ├── Admonition.tsx
│ ├── ApiFormState.tsx
│ ├── ApiGallery.module.css
│ ├── ApiGallery.tsx
│ ├── ApiPage.module.css
│ ├── ApiRefTable.tsx
│ ├── Bday.module.css
│ ├── BeekaiBuilderPage.module.css
│ ├── BeekaiBuilderPage.tsx
│ ├── BuilderPage.module.css
│ ├── BuilderPage.tsx
│ ├── ClipBoard.tsx
│ ├── CodeArea.module.css
│ ├── CodeArea.tsx
│ ├── CodeCompareSection.module.css
│ ├── CodeCompareSection.tsx
│ ├── CodePerfCompareSection.module.css
│ ├── CodePerfCompareSection.tsx
│ ├── CodeSandbox.tsx
│ ├── DevToolFeaturesList.module.css
│ ├── DevToolFeaturesList.tsx
│ ├── DevTools.module.css
│ ├── DevTools.tsx
│ ├── FeatureList.module.css
│ ├── FeaturesList.tsx
│ ├── Footer.module.css
│ ├── Footer.tsx
│ ├── Form.module.css
│ ├── Form.tsx
│ ├── FormFields.module.css
│ ├── FormFields.tsx
│ ├── FormStateApi.tsx
│ ├── FormStateTable.tsx
│ ├── GetStarted.module.css
│ ├── Header.module.css
│ ├── Header.tsx
│ ├── HomePage.module.css
│ ├── HomePage.tsx
│ ├── IsolateRender.module.css
│ ├── IsolateRender.tsx
│ ├── Menu
│ │ ├── Menu.tsx
│ │ ├── MenuLinks.ts
│ │ ├── SideMenu.module.css
│ │ └── index.ts
│ ├── Nav.module.css
│ ├── Nav.tsx
│ ├── Popup.module.css
│ ├── Popup.tsx
│ ├── ResourceList.tsx
│ ├── ResourcePage.module.css
│ ├── ResourcePageArticles.tsx
│ ├── ResourcePageBindings.tsx
│ ├── ResourcePageNewsletter.tsx
│ ├── ResourcePageVideos.tsx
│ ├── Search.module.css
│ ├── Search.tsx
│ ├── SortableContainer.module.css
│ ├── SortableContainer.tsx
│ ├── StarRepo.tsx
│ ├── TabGroup.module.css
│ ├── TabGroup.tsx
│ ├── Toggle.module.css
│ ├── Toggle.tsx
│ ├── TypeText.tsx
│ ├── UseController.tsx
│ ├── UseControllerContent.tsx
│ ├── UseControllerMethods.tsx
│ ├── UseFieldArray.tsx
│ ├── UseFieldArrayContent.tsx
│ ├── UseFormState.tsx
│ ├── Watcher.module.css
│ ├── Watcher.tsx
│ ├── codeExamples
│ │ ├── dependantFieldsTS.tsx
│ │ ├── devTool.tsx
│ │ ├── formState.ts
│ │ ├── formStateTs.ts
│ │ ├── formStateUseEffect.ts
│ │ ├── formStateUseEffectTs.ts
│ │ ├── reactHookFormCode.ts
│ │ ├── useController.ts
│ │ ├── useControllerCheckboxes.ts
│ │ ├── useControllerTs.ts
│ │ ├── useFieldArray.ts
│ │ ├── useFieldArrayArgument.ts
│ │ ├── useFieldArrayConditional.ts
│ │ ├── useFieldArrayFocus.ts
│ │ ├── useFieldArrayPreview.ts
│ │ ├── useFieldArrayTS.ts
│ │ └── useFormState.ts
│ ├── general-observer.tsx
│ ├── layout.css
│ ├── layout.tsx
│ ├── learnMore.tsx
│ ├── logic
│ │ ├── generateCode.ts
│ │ └── getEditLink.tsx
│ ├── mdx
│ │ ├── code.tsx
│ │ ├── mdx.tsx
│ │ ├── pre.tsx
│ │ ├── theme.ts
│ │ └── youtube.tsx
│ ├── selectNav.module.css
│ ├── selectNav.tsx
│ ├── seo.tsx
│ ├── sponsorsList.module.css
│ ├── sponsorsList.tsx
│ ├── useForm
│ │ ├── FormState.tsx
│ │ ├── Register.tsx
│ │ └── SetValue.tsx
│ └── utils
│ │ ├── copyClipBoard.ts
│ │ ├── goToBuilder.ts
│ │ └── useWindowSize.ts
├── content
│ ├── advanced-usage.mdx
│ ├── docs
│ │ ├── createFormControl.mdx
│ │ ├── formprovider.mdx
│ │ ├── usecontroller
│ │ │ └── controller.mdx
│ │ ├── useform.mdx
│ │ ├── useform
│ │ │ ├── clearerrors.mdx
│ │ │ ├── control.mdx
│ │ │ ├── form.mdx
│ │ │ ├── formstate.mdx
│ │ │ ├── getfieldstate.mdx
│ │ │ ├── getvalues.mdx
│ │ │ ├── handlesubmit.mdx
│ │ │ ├── register.mdx
│ │ │ ├── reset.mdx
│ │ │ ├── resetfield.mdx
│ │ │ ├── seterror.mdx
│ │ │ ├── setfocus.mdx
│ │ │ ├── setvalue.mdx
│ │ │ ├── trigger.mdx
│ │ │ ├── unregister.mdx
│ │ │ └── watch.mdx
│ │ ├── useformcontext.mdx
│ │ ├── useformstate.mdx
│ │ ├── useformstate
│ │ │ └── errormessage.mdx
│ │ └── usewatch.mdx
│ ├── faqs.mdx
│ ├── get-started.mdx
│ └── ts.mdx
├── data
│ ├── api.tsx
│ ├── builder.tsx
│ ├── devtools.tsx
│ ├── generic.tsx
│ ├── home.tsx
│ ├── nav.tsx
│ └── resources.tsx
├── pages
│ ├── 404.module.css
│ ├── 404.tsx
│ ├── [...slug].tsx
│ ├── _app.tsx
│ ├── _document.tsx
│ ├── about-us.tsx
│ ├── dev-tools.tsx
│ ├── docs.tsx
│ ├── docs
│ │ ├── usecontroller.tsx
│ │ └── usefieldarray.tsx
│ ├── form-builder.tsx
│ ├── index.tsx
│ ├── media.module.css
│ ├── media.tsx
│ ├── migrate-v6-to-v7.tsx
│ ├── providers
│ │ └── PostHogProvider.tsx
│ └── resources
│ │ ├── 3rd-party-bindings.tsx
│ │ ├── articles.tsx
│ │ ├── newsletters.tsx
│ │ └── videos.tsx
├── react-ko-form
│ └── components
│ │ ├── Banner.module.css
│ │ └── Banner.tsx
├── state
│ └── formData.ts
├── styles
│ ├── breakpoints.ts
│ ├── button.module.css
│ ├── colors.ts
│ ├── container.module.css
│ ├── table.module.css
│ └── typography.module.css
└── types
│ ├── global.d.ts
│ ├── little-state-machine.d.ts
│ └── types.ts
├── tsconfig.json
└── yarn.lock
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-unused-vars */
2 | const OFF = 0
3 | const WARN = 1
4 | const ERROR = 2
5 | /* eslint-enable @typescript-eslint/no-unused-vars */
6 |
7 | module.exports = {
8 | parser: "@typescript-eslint/parser",
9 | parserOptions: {
10 | ecmaVersion: 2020,
11 | sourceType: "module",
12 | ecmaFeatures: {
13 | jsx: true,
14 | },
15 | },
16 | env: {
17 | browser: true,
18 | node: true,
19 | },
20 | extends: [
21 | "plugin:react/recommended",
22 | "plugin:react-hooks/recommended",
23 | "plugin:@typescript-eslint/recommended",
24 | "plugin:jsx-a11y/recommended",
25 | "next",
26 | "plugin:react/jsx-runtime",
27 | ],
28 | settings: {
29 | react: {
30 | version: "detect",
31 | },
32 | },
33 | rules: {
34 | // typescript
35 | "@typescript-eslint/explicit-function-return-type": OFF,
36 | "@typescript-eslint/interface-name-prefix": OFF,
37 | "@typescript-eslint/explicit-module-boundary-types": OFF,
38 | // react
39 | "react/prop-types": OFF,
40 | "react/no-unescaped-entities": OFF,
41 | "react/jsx-curly-brace-presence": "warn",
42 | // jsx-ally
43 | "jsx-a11y/no-onchange": WARN,
44 | "import/no-anonymous-default-export": OFF,
45 | },
46 | }
47 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 20
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 3
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - pinned
8 | - security
9 | # Label to use when marking an issue as stale
10 | staleLabel:
11 | # Comment to post when marking an issue as stale. Set to `false` to disable
12 | markComment: >
13 | This issue has been automatically marked as stale because it has not had
14 | recent activity. It will be closed if no further activity occurs. Thank you
15 | for your contributions.
16 | # Comment to post when closing a stale issue. Set to `false` to disable
17 | closeComment: false
18 |
--------------------------------------------------------------------------------
/.github/workflows/lock-issue.yml:
--------------------------------------------------------------------------------
1 | name: 'Lock Issues'
2 |
3 | on:
4 | workflow_dispatch:
5 | schedule:
6 | - cron: '0 0,6,12,18 * * *'
7 |
8 | permissions:
9 | issues: write
10 |
11 | concurrency:
12 | group: lock
13 |
14 | jobs:
15 | action:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: dessant/lock-threads@v3
19 | with:
20 | github-token: ${{ secrets.GITHUB_TOKEN }}
21 | issue-inactive-days: 60
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .yarn/*
7 | !.yarn/patches
8 | !.yarn/releases
9 | !.yarn/plugins
10 | !.yarn/sdks
11 | !.yarn/versions
12 | .pnp.*
13 |
14 |
15 | # testing
16 | /coverage
17 |
18 | # production
19 | /build
20 | /dist
21 |
22 | # misc
23 | .DS_Store
24 | .env.local
25 | .env.development.local
26 | .env.test.local
27 | .env.production.local
28 |
29 | npm-debug.log*
30 | yarn-debug.log*
31 | yarn-error.log*
32 | .idea/
33 | .idea
34 | .cache/
35 | package-lock.json
36 | tsconfig.tsbuildinfo
37 | .next/
38 |
39 | # contentlayer
40 | .contentlayer
41 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "endOfLine": "lf",
3 | "semi": false,
4 | "singleQuote": false,
5 | "tabWidth": 2,
6 | "trailingComma": "es5"
7 | }
8 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib",
3 | "editor.defaultFormatter": "esbenp.prettier-vscode",
4 | "prettier.requireConfig": true,
5 | "editor.formatOnSave": true,
6 |
7 | "[typescript]": {
8 | "editor.defaultFormatter": "esbenp.prettier-vscode"
9 | },
10 | "[javascript]": {
11 | "editor.defaultFormatter": "esbenp.prettier-vscode"
12 | },
13 | "[json]": {
14 | "editor.defaultFormatter": "esbenp.prettier-vscode"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to `React Hook Form` (The Docs)
2 |
3 | As the creators and maintainers of this project, we want to ensure that `react-hook-form` lives and continues to grow and evolve. We would like to encourage everyone to help and support this library by contributing.
4 |
5 | ## Code contributions
6 |
7 | Here is a quick guide to doing code contributions to the library.
8 |
9 | 1. Fork and clone the repo to your local machine `git clone https://github.com/YOUR_GITHUB_USERNAME/website.git`
10 |
11 | 2. Create a new branch from `master` with a meaningful name for a new feature or an issue you want to work on: `git checkout -b your-meaningful-branch-name`
12 |
13 | 3. Install packages by running:
14 |
15 | > yarn
16 |
17 | 4. Startup a local version of the docs
18 |
19 | > yarn start
20 |
21 | 5. Ensure your code is formatted properly
22 |
23 | > yarn format
24 |
25 | 6. Push your branch: `git push -u origin your-meaningful-branch-name`
26 |
27 | 7. Submit a pull request to the upstream react-hook-form repository.
28 |
29 | 8. Choose a descriptive title and describe your changes briefly.
30 |
31 | ## Coding style
32 |
33 | Please follow the coding style of the project. React Hook Form uses prettier. If possible, enable the prettier plugin in your editor to get real-time feedback. The formatting can be run manually with the following command: `yarn format`
34 |
35 | ## License
36 |
37 | By contributing your code to the react-hook-form GitHub repository, you agree to license your contribution under the MIT license.
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019-present Beier(Bill) Luo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
8 |
9 | ## 목표
10 |
11 | **React-Ko-Form** 레포지토리는 **React Hook Form**의 공식 문서([https://react-hook-form.com/docs](https://react-hook-form.com/docs)) 를 한국어로 번역하는 프로젝트입니다. 이 레포지토리는 **비공식** 한국어 문서로서, React Hook Form의 공식 레포지토리와는 별개로 유지됩니다.
12 |
13 | 이 프로젝트는 React Hook Form을 사용하는 한국어 개발자들의 편의성을 높이는 것을 목표로 합니다.
14 |
15 | 공식 문서 업데이트 및 changes 발생 시에는 그에 맞춰 업데이트될 예정입니다.
16 | 관련 업데이트는 Issue 탭에서 공유됩니다.
17 |
18 | ## 위키
19 |
20 | 현재 react ko form에서 저희 내부적으로 공통화 된 번역 [위키 룰](https://github.com/hamsurang/react-ko-form/wiki/react%E2%80%90ko%E2%80%90form%EC%9D%98-%EB%B2%88%EC%97%AD-%EA%B7%9C%EC%B9%99
21 | )입니다.
22 |
23 | 작업 전 꼭 참고해 주시기 바랍니다.
24 | 감사합니다.
25 |
26 |
27 | ## 설치 및 실행
28 |
29 | ```bash
30 | pnpm install
31 | pnpm run dev # dev 서버 실행
32 | ```
33 |
34 |
35 | ## 기여자
36 |
37 | 이 프로젝트에 기여해 주신 멋진 분들께 감사드립니다.
38 | [기여자가 되려면](https://github.com/hamsurang/react-ko-form/blob/master-ko/.github/CONTRIBUTING.md)
39 |
--------------------------------------------------------------------------------
/contentlayer.config.ts:
--------------------------------------------------------------------------------
1 | import { defineDocumentType, makeSource } from "contentlayer/source-files"
2 | import { remarkHeadingId } from "remark-custom-heading-id"
3 | import remarkGfm from "remark-gfm"
4 | import rehypeMdxCodeProps from "rehype-mdx-code-props"
5 | import emoji from "remark-emoji"
6 | import * as sidebar from "./src/components/Menu/MenuLinks"
7 |
8 | export const Doc = defineDocumentType(() => ({
9 | name: "Doc",
10 | contentType: "mdx",
11 | filePathPattern: "**/*.mdx",
12 | fields: {
13 | title: { type: "string", required: true },
14 | description: { type: "string", required: true },
15 | sidebar: {
16 | type: "enum",
17 | options: [
18 | "apiLinks",
19 | "advancedLinks",
20 | "tsLinks",
21 | "faqLinks",
22 | "getStartedLinks",
23 | ],
24 | required: true,
25 | },
26 | },
27 | computedFields: {
28 | slug: {
29 | type: "string",
30 | resolve: (doc) => `/${doc._raw.flattenedPath}`,
31 | },
32 | slugAsParams: {
33 | type: "string",
34 | resolve: (doc) => doc._raw.flattenedPath.split("/").slice(1).join("/"),
35 | },
36 | segment: {
37 | type: "list",
38 | resolve: (doc) => doc._raw.flattenedPath.split("/"),
39 | },
40 | pages: {
41 | type: "list",
42 | resolve: (doc) => sidebar[doc.sidebar] ?? [],
43 | },
44 | },
45 | }))
46 |
47 | export default makeSource({
48 | contentDirPath: "src/content",
49 | documentTypes: [Doc],
50 | mdx: {
51 | remarkPlugins: [remarkGfm, remarkHeadingId, emoji],
52 | rehypePlugins: [rehypeMdxCodeProps],
53 | },
54 | })
55 |
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/next.config.mjs:
--------------------------------------------------------------------------------
1 | import { withContentlayer } from "next-contentlayer"
2 | import withBundleAnalyzer from "@next/bundle-analyzer"
3 |
4 | /** @type {import('next').NextConfig} */
5 | const nextConfig = {
6 | eslint: {
7 | ignoreDuringBuilds: true,
8 | },
9 | typescript: {
10 | ignoreBuildErrors: true,
11 | },
12 | reactStrictMode: true,
13 | pageExtensions: ["ts", "tsx", "js", "jsx", "md", "mdx"],
14 | }
15 |
16 | const bundleAnalyzer = withBundleAnalyzer({
17 | enabled: process.env.ANALYZE === "true",
18 | })
19 |
20 | export default bundleAnalyzer(withContentlayer(nextConfig))
21 |
--------------------------------------------------------------------------------
/origin-src/components/Admonition.module.css:
--------------------------------------------------------------------------------
1 | .admonition {
2 | margin-top: 1rem;
3 | margin-bottom: 1em;
4 | padding: 15px 30px 15px 15px;
5 | border-radius: 0.4rem;
6 | }
7 |
8 | .admonitionIcon {
9 | display: inline-block;
10 | vertical-align: middle;
11 | margin-right: 0.2em;
12 | }
13 |
14 | .admonitionIcon svg {
15 | display: inline-block;
16 | width: 22px;
17 | height: 22px;
18 | stroke-width: 0;
19 | }
20 |
21 | .admonitionIcon svg {
22 | stroke: var(--color-black);
23 | fill: var(--color-black);
24 | }
25 |
26 | :global(.dark) .admonitionIcon svg {
27 | stroke: rgb(253, 253, 254);
28 | fill: rgb(253, 253, 254);
29 | }
30 |
31 | .admonitionContent > :last-child {
32 | margin-bottom: 0;
33 | }
34 |
35 | /** Customization */
36 | .admonitionWarning {
37 | background-color: rgba(230, 126, 34, 0.1);
38 | border-left: 8px solid var(--color-orange);
39 | }
40 |
41 | .admonitionTip {
42 | background-color: rgba(46, 204, 113, 0.1);
43 | border-left: 8px solid var(--color-green);
44 | }
45 |
46 | .admonitionCaution {
47 | background-color: rgba(231, 76, 60, 0.1);
48 | border-left: 8px solid var(--color-secondary);
49 | }
50 |
51 | .admonitionImportant {
52 | background-color: rgb(25, 60, 71, 0.1);
53 | border-left: 8px solid var(--color-blue);
54 | }
55 |
56 | .admonitionNote {
57 | background-color: rgb(71, 71, 72, 0.1);
58 | border-left: 8px solid var(--color-text);
59 | }
60 |
61 | .admonitionQuestion {
62 | background-color: rgba(8, 61, 119, 0.1);
63 | border-left: 8px solid var(--color-light-blue);
64 | }
65 |
--------------------------------------------------------------------------------
/origin-src/components/ApiPage.module.css:
--------------------------------------------------------------------------------
1 | .mobileTypeText {
2 | font-weight: 400;
3 | font-size: 15px;
4 | font-family: monospace;
5 | font-variant-ligatures: none;
6 | color: var(--color-light-pink);
7 | margin-top: 10px;
8 | display: block;
9 | }
10 |
11 | .quickSelect {
12 | position: relative;
13 | max-width: 320px;
14 | margin: 0 auto;
15 | }
16 |
17 | .quickSelect:after {
18 | content: "▼";
19 | font-size: 15px;
20 | right: 17%;
21 | top: 12px;
22 | position: absolute;
23 | pointer-events: none;
24 | }
25 |
26 | .quickSelect > select {
27 | border-radius: 4px;
28 | border: 1px solid var(--color-light-blue);
29 | appearance: none;
30 | background: none;
31 | color: white;
32 | margin: 0.67em auto 20px;
33 | display: block;
34 | text-align: center;
35 | text-align-last: center;
36 | font-size: 2rem;
37 | font-weight: lighter;
38 | position: relative;
39 | padding: 10px 30px;
40 | max-width: 240px;
41 | }
42 |
43 | .versionToggle {
44 | position: absolute;
45 | right: 20px;
46 | }
47 |
48 | @media (min-width: 768px) {
49 | .hiddenMenu > h1 {
50 | display: block;
51 | }
52 |
53 | .hiddenMenu > div {
54 | display: none;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/origin-src/components/ClipBoard.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react"
2 | import generic from "../data/generic"
3 |
4 | const ClipBoard = ({
5 | className,
6 | onClick,
7 | }: {
8 | onClick: () => void
9 | className?: string
10 | }) => {
11 | const [copiedCode, setCopiedCode] = useState(false)
12 |
13 | useEffect(() => {
14 | if (!copiedCode) {
15 | return
16 | }
17 |
18 | const timerId = setTimeout(() => {
19 | setCopiedCode(false)
20 | }, 3000)
21 |
22 | return () => {
23 | clearTimeout(timerId)
24 | }
25 | }, [copiedCode])
26 |
27 | return (
28 |
38 | )
39 | }
40 |
41 | export default ClipBoard
42 |
--------------------------------------------------------------------------------
/origin-src/components/CodeArea.module.css:
--------------------------------------------------------------------------------
1 | .buttonWrapper {
2 | display: flex;
3 | position: absolute;
4 | top: 10px;
5 | right: 5px;
6 | }
7 |
8 | .button {
9 | border: none;
10 | color: white;
11 | border-radius: 0;
12 | font-size: 13px;
13 | padding: 0 10px;
14 | right: 20px;
15 | z-index: 1;
16 | top: 10px;
17 | display: none;
18 | cursor: pointer;
19 | text-transform: uppercase;
20 | height: 34px;
21 | align-items: center;
22 | margin: 0 3px;
23 | }
24 |
25 | .codeLink {
26 | background: var(--color-light-blue);
27 | border: 1px solid transparent;
28 | }
29 |
30 | .button:hover {
31 | background: var(--color-secondary);
32 | color: white;
33 | }
34 |
35 | @media (min-width: 768px) {
36 | .button {
37 | display: flex;
38 | }
39 | }
40 |
41 | .copyButton {
42 | background: none;
43 | border: 1px solid transparent;
44 | color: currentColor;
45 | }
46 |
47 | .active,
48 | .copyButton:hover {
49 | background: none;
50 | border: 1px solid var(--color-secondary);
51 | color: white;
52 | }
53 |
54 | .active,
55 | .copyButton:hover span {
56 | background: var(--color-primary);
57 | }
58 |
59 | .linkToSandBox {
60 | text-decoration: none;
61 | line-height: 2;
62 | right: 115px;
63 | color: inherit;
64 | }
65 |
66 | .linkToSandBox > svg {
67 | display: inline-block;
68 | height: 18px;
69 | position: relative;
70 | margin-right: 8px;
71 | }
72 |
--------------------------------------------------------------------------------
/origin-src/components/CodeCompareSection.module.css:
--------------------------------------------------------------------------------
1 | .gridView {
2 | display: flex;
3 | flex-direction: column;
4 | }
5 |
6 | .gridView > div:first-child {
7 | order: 1;
8 | }
9 |
10 | .gridView iframe {
11 | display: none;
12 | box-shadow: 0 0 20px #010817;
13 | }
14 |
15 | .fullScreen {
16 | background: none;
17 | color: white;
18 | position: absolute;
19 | z-index: 1;
20 | right: 0;
21 | font-size: 12px;
22 | border-top: none;
23 | border-right: none;
24 | border-color: var(--color-secondary);
25 | border-bottom-left-radius: 4px;
26 | display: none;
27 | }
28 |
29 | .fullScreen:hover {
30 | background: var(--color-light-pink);
31 | }
32 |
33 | @media (min-width: 1000px) {
34 | .gridView {
35 | display: grid;
36 | grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
37 | grid-column-gap: 40px;
38 | max-width: 1024px;
39 | margin: 0 auto;
40 | }
41 |
42 | .gridView iframe {
43 | display: block;
44 | }
45 |
46 | .gridView > div:first-child {
47 | order: 0;
48 | }
49 |
50 | .fullScreen {
51 | display: block;
52 | }
53 |
54 | .display {
55 | display: none;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/origin-src/components/CodeSandbox.tsx:
--------------------------------------------------------------------------------
1 | import styles from "./CodeArea.module.css"
2 |
3 | export const CodeSandBoxLink = ({
4 | url,
5 | isJS,
6 | isExpo,
7 | }: {
8 | url?: string
9 | isExpo?: boolean
10 | isJS?: boolean
11 | }) => (
12 |
18 | {!isExpo && (
19 |
27 | )}{" "}
28 | {isExpo ? "Expo" : "CodeSandbox"}{" "}
29 | {typeof isJS === "boolean" && (
30 |
36 | {isJS ? "JS" : "TS"}
37 |
38 | )}
39 |
40 | )
41 |
--------------------------------------------------------------------------------
/origin-src/components/DevToolFeaturesList.module.css:
--------------------------------------------------------------------------------
1 | .featuresContent {
2 | text-align: center;
3 | }
4 |
5 | .featuresContent h3 {
6 | font-weight: 400;
7 | font-size: 20px;
8 | margin-top: 10px;
9 | }
10 |
11 | .featuresContent svg {
12 | fill: var(--color-text);
13 | width: 50px;
14 | display: block;
15 | margin: 0 auto;
16 | height: 60px;
17 | }
18 |
19 | .featuresContent > article {
20 | padding-bottom: 30px;
21 | }
22 |
23 | .featuresContent > article > div {
24 | transform: scale(0);
25 | }
26 |
27 | .features {
28 | margin-top: -60px;
29 | }
30 |
31 | .features > h2 {
32 | margin-bottom: 30px;
33 | }
34 |
35 | @media (min-width: 768px) {
36 | .featuresContent h3 {
37 | font-size: 22px;
38 | }
39 |
40 | .features > h2 {
41 | max-width: 450px;
42 | margin: 0 auto 20px;
43 | }
44 |
45 | .features {
46 | margin-top: 60px;
47 | }
48 |
49 | .featuresContent {
50 | display: grid;
51 | grid-template-columns: repeat(3, 1fr);
52 | grid-column-gap: 40px;
53 | max-width: 800px;
54 | margin: 20px auto 30px;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/origin-src/components/DevTools.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | display: grid;
3 | }
4 |
5 | .devToolImg {
6 | height: 230px;
7 | margin: 30px auto 80px;
8 | display: block;
9 | cursor: not-allowed;
10 | border-radius: 5px;
11 | }
12 |
13 | .devTool ::-webkit-scrollbar {
14 | }
15 |
16 | .devTool ::-webkit-scrollbar-track {
17 | background: inherit;
18 | }
19 |
20 | .devTool ::-webkit-scrollbar-thumb {
21 | background: grey;
22 | }
23 |
24 | .devTool ::-webkit-scrollbar-thumb:hover {
25 | background: black;
26 | }
27 |
28 | .demo {
29 | display: grid;
30 | grid-gap: 30px;
31 | max-width: 768px;
32 | margin: 0 auto;
33 | }
34 |
35 | .demo > div:first-child {
36 | order: 2;
37 | }
38 |
39 | @media (min-width: 768px) {
40 | .devToolImg {
41 | max-width: 600px;
42 | margin: 50px auto 0;
43 | display: block;
44 | height: auto;
45 | border-radius: 8px;
46 | min-height: 420px;
47 | }
48 |
49 | .demo {
50 | display: grid;
51 | grid-gap: 30px;
52 | grid-template-columns: 1fr 1fr;
53 | max-width: 768px;
54 | margin: 0 auto;
55 | }
56 |
57 | .demo > div:first-child {
58 | order: 0;
59 | }
60 | }
61 |
62 | @media (min-width: 1024px) {
63 | .devTool {
64 | display: block;
65 | }
66 |
67 | .devToolImg {
68 | max-width: 800px;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/origin-src/components/FeatureList.module.css:
--------------------------------------------------------------------------------
1 | .featuresContent {
2 | text-align: center;
3 | }
4 |
5 | .featuresContent h3 {
6 | font-weight: 500;
7 | font-size: 20px;
8 | margin-top: 10px;
9 | }
10 |
11 | .featuresContent svg {
12 | width: 50px;
13 | display: block;
14 | margin: 0 auto;
15 | height: 60px;
16 | }
17 |
18 | .featuresContent > article {
19 | padding-bottom: 30px;
20 | }
21 |
22 | .featuresContent > article > div {
23 | transform: scale(0);
24 | }
25 |
26 | .features {
27 | margin-top: -60px;
28 | }
29 |
30 | .features > h2 {
31 | margin-bottom: 30px;
32 | }
33 |
34 | @media (min-width: 768px) {
35 | .featuresContent h3 {
36 | font-size: 22px;
37 | }
38 |
39 | .features > h2 {
40 | max-width: 450px;
41 | margin: 0 auto 20px;
42 | }
43 |
44 | .features {
45 | margin-top: 60px;
46 | margin-bottom: 60px;
47 | }
48 |
49 | .featuresContent {
50 | display: grid;
51 | grid-template-columns: repeat(3, 1fr);
52 | grid-column-gap: 30px;
53 | max-width: 1024px;
54 | margin: 40px auto 30px;
55 | }
56 | }
57 |
58 | @media (min-width: 1280px) {
59 | .featuresContent {
60 | grid-template-columns: repeat(6, 1fr);
61 | grid-column-gap: 25px;
62 | max-width: 1480px;
63 | }
64 |
65 | .featuresContent > article {
66 | padding-bottom: 0;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/origin-src/components/Footer.module.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | padding: 40px 0;
3 | font-size: 0.8rem;
4 | font-weight: 400;
5 | text-align: center;
6 | }
7 |
8 | .footer a {
9 | color: var(--color-footer);
10 | text-decoration: none;
11 | }
12 |
13 | .footer a:hover {
14 | color: var(--color-light-pink);
15 | text-decoration: none;
16 | }
17 |
18 | .footer > p {
19 | font-size: 13px;
20 | }
21 |
22 | .links {
23 | border-bottom: 1px solid var(--color-light-pink);
24 | max-width: 900px;
25 | margin: 0 auto 20px;
26 | padding: 0 0 10px 0;
27 | display: block;
28 | }
29 |
30 | .links > li {
31 | display: inline-flex;
32 | }
33 |
34 | .links > li > a {
35 | text-decoration: none;
36 | color: var(--color-text);
37 | padding: 10px 12px;
38 | min-width: 48px;
39 | min-height: 48px;
40 | }
41 |
42 | a.link {
43 | color: var(--color-primary);
44 | }
45 |
46 | .logoGroup {
47 | display: flex;
48 | justify-content: center;
49 | align-items: center;
50 | gap: 1rem;
51 | }
52 |
53 | .logoGroup img {
54 | width: 100px;
55 | }
56 |
57 | .heading {
58 | font-size: 0.6rem;
59 | font-weight: 600;
60 | margin-bottom: -0.2rem;
61 | }
62 |
--------------------------------------------------------------------------------
/origin-src/components/Form.module.css:
--------------------------------------------------------------------------------
1 | .code {
2 | padding: 0 20px;
3 | white-space: pre-wrap;
4 | font-size: 0.7rem;
5 | line-height: 1.6;
6 | }
7 |
8 | .wrapper {
9 | display: grid;
10 | min-height: 700px;
11 | transition: 1s all;
12 | grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
13 | grid-column-gap: 40px;
14 | max-width: 1440px;
15 | margin: 20px auto 0;
16 | }
17 |
18 | .demoForm {
19 | flex: 1;
20 | }
21 |
22 | .demoForm > select,
23 | .demoForm > input,
24 | .input {
25 | display: block;
26 | box-sizing: border-box;
27 | width: 100%;
28 | border-radius: 4px;
29 | padding: 6px 10px;
30 | margin-bottom: 10px;
31 | font-size: 0.9rem;
32 | }
33 |
34 | .demoForm > select:not([multiple]) {
35 | height: 43px;
36 | }
37 |
--------------------------------------------------------------------------------
/origin-src/components/FormFields.module.css:
--------------------------------------------------------------------------------
1 | .radioGroup {
2 | display: flex;
3 | margin-bottom: 20px;
4 | }
5 |
6 | .radioGroup > label:not(:last-child) {
7 | margin-right: 20px;
8 | }
9 |
--------------------------------------------------------------------------------
/origin-src/components/FormStateTable.tsx:
--------------------------------------------------------------------------------
1 | import generic from "../data/generic"
2 | import API from "../data/api"
3 | import typographyStyles from "../styles/typography.module.css"
4 | import tableStyles from "../styles/table.module.css"
5 | import { FormStateApi } from "./FormStateApi"
6 |
7 | export default function FormStateTable({ api }: { api: typeof API }) {
8 | return (
9 | <>
10 |
11 | Return
12 |
13 |
14 |
15 |
16 |
17 | {generic.name} |
18 | {generic.type} |
19 | {generic.description} |
20 |
21 |
22 |
23 |
24 |
25 | >
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/origin-src/components/GetStarted.module.css:
--------------------------------------------------------------------------------
1 | .copyButton {
2 | display: none;
3 | background: var(--color-light-blue);
4 | color: white;
5 | font-size: 13px;
6 | float: right;
7 | text-transform: uppercase;
8 | border: 1px solid transparent;
9 | margin-top: -2px;
10 | cursor: pointer;
11 | }
12 |
13 | .copyButton:hover {
14 | background: none;
15 | border: 1px solid var(--color-secondary);
16 | color: white;
17 | }
18 |
19 | .copyButton:hover span {
20 | background: var(--color-primary);
21 | }
22 |
23 | @media (min-width: 768px) {
24 | .copyButton {
25 | display: inline-block;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/origin-src/components/HomePage.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | padding: 0 20px 50px;
3 | position: relative;
4 | }
5 |
6 | .feedback {
7 | margin-top: 40px;
8 | }
9 |
10 | .feedback > div {
11 | border-radius: 15px;
12 | margin-bottom: 20px;
13 | }
14 |
15 | .feedback svg {
16 | margin: 0 auto 10px;
17 | width: 45px;
18 | }
19 |
20 | .feedback > div > p {
21 | font-size: 15px;
22 | text-align: left;
23 | padding: 20px 0;
24 | }
25 |
26 | @media (min-width: 768px) {
27 | .feedback {
28 | display: grid;
29 | grid-template-columns: repeat(3, 1fr);
30 | grid-gap: 50px;
31 | }
32 |
33 | .feedback > div {
34 | margin-bottom: 0;
35 | }
36 | }
37 |
38 | @media (min-width: 1024px) {
39 | .root {
40 | padding: 0 50px;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/origin-src/components/IsolateRender.module.css:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | display: grid;
3 | grid-gap: 20px;
4 | margin-top: 20px;
5 | grid-template-columns: 1fr 1fr;
6 | position: relative;
7 | }
8 |
9 | .wrapper > div {
10 | display: none;
11 | }
12 |
13 | .wrapper p {
14 | font-size: 45px;
15 | font-weight: 800;
16 | margin-top: 160px;
17 | line-height: 1.4;
18 | }
19 |
20 | .wrapper h2 {
21 | font-size: 14px;
22 | }
23 |
24 | .externalComponent {
25 | font-size: 14px;
26 | border: 1px solid var(--color-secondary);
27 | padding: 10px 0;
28 | border-radius: 4px;
29 | margin: 20px 0;
30 | }
31 |
32 | .line {
33 | position: absolute;
34 | width: 1px;
35 | background: var(--color-blue);
36 | height: 44%;
37 | left: 50%;
38 | top: 30%;
39 | z-index: -1;
40 | }
41 |
42 | @media (min-width: 768px) {
43 | .wrapper {
44 | grid-gap: 40px;
45 | grid-template-columns: 1fr 65px 1fr;
46 | }
47 |
48 | .wrapper > div {
49 | display: block;
50 | }
51 |
52 | .wrapper h2 {
53 | font-size: 24px;
54 | font-weight: 400;
55 | padding-bottom: 10px;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/origin-src/components/Menu/index.ts:
--------------------------------------------------------------------------------
1 | import Menu from "./Menu"
2 | import {
3 | apiLinks,
4 | faqLinks,
5 | advancedLinks,
6 | tsLinks,
7 | getStartedLinks,
8 | } from "./MenuLinks"
9 |
10 | const links = {
11 | apiLinks,
12 | faqLinks,
13 | advancedLinks,
14 | tsLinks,
15 | getStartedLinks,
16 | }
17 |
18 | export {
19 | Menu,
20 | apiLinks,
21 | faqLinks,
22 | advancedLinks,
23 | tsLinks,
24 | getStartedLinks,
25 | links,
26 | }
27 |
--------------------------------------------------------------------------------
/origin-src/components/Popup.module.css:
--------------------------------------------------------------------------------
1 | .iconStyle,
2 | .icon,
3 | .button {
4 | border-radius: 50%;
5 | border: none;
6 | height: 18px;
7 | width: 18px;
8 | font-size: 15px;
9 | display: inline-flex;
10 | margin-left: 10px;
11 | justify-content: center;
12 | align-items: center;
13 | line-height: 1;
14 | }
15 |
16 | .icon {
17 | border: 1px solid var(--color-text);
18 | margin-left: 0;
19 | margin-right: 5px;
20 | }
21 |
22 | .root {
23 | font-weight: bold;
24 | position: relative;
25 | }
26 |
27 | .root > span {
28 | font-size: 14px !important;
29 | margin-left: 10px;
30 | font-weight: 400;
31 | display: inline-block;
32 | overflow: hidden;
33 | position: relative;
34 | top: 5px;
35 | }
36 |
37 | .root > span > span {
38 | display: inline-block;
39 | position: relative;
40 | font-family: sans-serif;
41 | }
42 |
43 | .button {
44 | cursor: pointer;
45 | }
46 |
47 | .button:hover {
48 | background: var(--color-light-pink);
49 | color: white;
50 | }
51 |
--------------------------------------------------------------------------------
/origin-src/components/Popup.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react"
2 | import { Animate } from "react-simple-animate"
3 | import styles from "./Popup.module.css"
4 |
5 | function Popup({
6 | message,
7 | top,
8 | iconOnly,
9 | }: {
10 | iconOnly?: boolean
11 | message?: string
12 | top?: number
13 | }) {
14 | const [tipShow, setTipShow] = useState(false)
15 |
16 | if (iconOnly) {
17 | return !
18 | }
19 |
20 | return (
21 |
22 |
30 |
31 | (
40 |
41 | {message || <>React Native: compatible with Controller>}
42 |
43 | )}
44 | />
45 |
46 |
47 | )
48 | }
49 |
50 | export default Popup
51 |
--------------------------------------------------------------------------------
/origin-src/components/ResourcePageArticles.tsx:
--------------------------------------------------------------------------------
1 | import containerStyle from "../styles/container.module.css"
2 | import styles from "./ResourcePage.module.css"
3 | import Footer from "./Footer"
4 | import generic from "../data/generic"
5 | import ResourceList from "./ResourceList"
6 | import resources from "../data/resources"
7 | import StarRepo from "./StarRepo"
8 |
9 | export default function ResourcePageCondensed() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/origin-src/components/ResourcePageBindings.tsx:
--------------------------------------------------------------------------------
1 | import containerStyle from "../styles/container.module.css"
2 | import styles from "./ResourcePage.module.css"
3 | import Footer from "./Footer"
4 | import generic from "../data/generic"
5 | import ResourceList from "./ResourceList"
6 | import resources from "../data/resources"
7 | import StarRepo from "./StarRepo"
8 |
9 | export default function ResourcePageBinding() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/origin-src/components/ResourcePageNewsletter.tsx:
--------------------------------------------------------------------------------
1 | import containerStyle from "../styles/container.module.css"
2 | import styles from "./ResourcePage.module.css"
3 | import Footer from "./Footer"
4 | import generic from "../data/generic"
5 | import ResourceList from "./ResourceList"
6 | import resources from "../data/resources"
7 | import StarRepo from "./StarRepo"
8 |
9 | export default function ResourcePageNewsletter() {
10 | return (
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/origin-src/components/ResourcePageVideos.tsx:
--------------------------------------------------------------------------------
1 | import containerStyle from "../styles/container.module.css"
2 | import styles from "./ResourcePage.module.css"
3 | import Footer from "./Footer"
4 | import generic from "../data/generic"
5 | import ResourceList from "./ResourceList"
6 | import resources from "../data/resources"
7 | import StarRepo from "./StarRepo"
8 |
9 | export default function ResourcePageVideos() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/origin-src/components/Search.module.css:
--------------------------------------------------------------------------------
1 | .searchForm {
2 | margin-right: 12px;
3 | position: relative;
4 | }
5 |
6 | .whiteText {
7 | color: white !important;
8 | }
9 |
10 | .searchBar {
11 | padding: 0 10px;
12 | width: 26px;
13 | border-radius: 25px;
14 | font-size: 16px;
15 | line-height: 24px;
16 | height: 26px;
17 | z-index: 1;
18 | cursor: pointer;
19 | color: var(--color-primary) !important;
20 | }
21 |
22 | .searchBarOpen {
23 | padding: 3px 14px;
24 | width: 150px;
25 | }
26 |
27 | .searchBarOpen:focus {
28 | outline: none;
29 | border: 1px solid var(--color-light-pink);
30 | cursor: default;
31 | }
32 |
33 | .icon {
34 | color: black !important;
35 | position: absolute;
36 | left: 7px;
37 | z-index: 22;
38 | top: 5px;
39 | pointer-events: none;
40 | }
41 |
42 | @media (min-width: 1600px) {
43 | .searchBar {
44 | width: 150px;
45 | padding: 3px 14px;
46 | }
47 |
48 | .icon {
49 | display: none;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/origin-src/components/Search.tsx:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from "react"
2 | import clsx from "clsx"
3 | import searchStyles from "./Search.module.css"
4 | import useWindowSize from "./utils/useWindowSize"
5 | import { LARGE_SCREEN } from "../styles/breakpoints"
6 |
7 | const Search = ({
8 | focus,
9 | setFocus,
10 | }: {
11 | focus: boolean
12 | setFocus: (value: boolean) => void
13 | }) => {
14 | const { width } = useWindowSize()
15 | const searchRef = useRef(null)
16 |
17 | useEffect(() => {
18 | window.docsearch?.({
19 | appId: "Z2CKVVT2QA",
20 | apiKey: "c56a3f265ffbf85c2c654f865cb09164",
21 | indexName: "react-hook-form",
22 | inputSelector: "#algolia-doc-search",
23 | })
24 |
25 | return () => {
26 | setFocus(false)
27 | }
28 | }, [setFocus])
29 |
30 | useEffect(() => {
31 | if (LARGE_SCREEN <= width) {
32 | setFocus(true)
33 | } else {
34 | setFocus(false)
35 | searchRef.current?.blur()
36 | }
37 | }, [setFocus, width])
38 |
39 | return (
40 | <>
41 |
63 |
64 | >
65 | )
66 | }
67 |
68 | export default Search
69 |
--------------------------------------------------------------------------------
/origin-src/components/SortableContainer.module.css:
--------------------------------------------------------------------------------
1 | .list {
2 | border: 1px solid var(--color-light-blue);
3 | padding: 14px 14px 14px 50px;
4 | border-radius: 4px;
5 | margin-bottom: 10px;
6 | background: var(--color-primary);
7 | cursor: move;
8 | position: relative;
9 | list-style: none;
10 | color: white;
11 | }
12 |
13 | .list > svg {
14 | fill: white;
15 | display: inline-block;
16 | width: 20px;
17 | position: absolute;
18 | left: 15px;
19 | top: 17px;
20 | }
21 |
22 | .editPanel {
23 | float: right;
24 | }
25 |
26 | .editPanel > button {
27 | position: relative;
28 | color: white;
29 | top: -2px;
30 | font-size: 14px;
31 | cursor: pointer;
32 | padding: 1px 8px;
33 | background: var(--color-light-blue);
34 | border: 1px solid transparent;
35 | text-transform: uppercase;
36 | letter-spacing: 1px;
37 | }
38 |
39 | .editPanel > button:hover {
40 | background: var(--color-primary);
41 | border: 1px solid var(--color-secondary);
42 | }
43 |
44 | .editPanel > button:first-child {
45 | margin-right: 14px;
46 | }
47 |
48 | .sortableWrapper {
49 | margin-top: 30px;
50 | }
51 |
52 | .sortableWrapper > ul {
53 | margin-left: 0;
54 | padding-left: 0;
55 | }
56 |
--------------------------------------------------------------------------------
/origin-src/components/StarRepo.tsx:
--------------------------------------------------------------------------------
1 | import generic from "../data/generic"
2 | import buttonStyles from "../styles/button.module.css"
3 | import containerStyles from "../styles/container.module.css"
4 |
5 | export default function StarRepo() {
6 | return (
7 |
11 |
{generic.needYourSupport.title}
12 |
{generic.needYourSupport.description}
13 |
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/origin-src/components/TabGroup.module.css:
--------------------------------------------------------------------------------
1 | .buttonTabGroup {
2 | display: grid;
3 | grid-auto-flow: column;
4 | }
5 |
6 | .buttonTabGroup > button {
7 | color: var(--color-text);
8 | background: var(--color-background);
9 | padding: 5px 8px 5px;
10 | font-size: 12px;
11 | border: none;
12 | transition: 0.3s all;
13 | text-transform: uppercase;
14 | }
15 |
16 | .buttonTabGroup > button:nth-child(n + 2) {
17 | margin-left: 3px;
18 | }
19 |
20 | .buttonTabGroup > button:hover {
21 | background: var(--color-secondary);
22 | }
23 |
24 | .buttonTabGroup > button:disabled {
25 | border-top: 1px solid var(--color-secondary);
26 | background: var(--color-primary);
27 | color: white;
28 | cursor: not-allowed;
29 | }
30 |
31 | @media (min-width: 768px) {
32 | .buttonTabGroup > button {
33 | padding: 5px 20px 5px;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/origin-src/components/TabGroup.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react"
2 | import type { ReactNode } from "react"
3 | import styles from "./TabGroup.module.css"
4 |
5 | const TabGroup = ({
6 | children,
7 | buttonLabels,
8 | }: {
9 | children: ReactNode[]
10 | buttonLabels: string[]
11 | }) => {
12 | const [index, setIndex] = useState(0)
13 |
14 | return (
15 |
16 |
20 | {buttonLabels.map((label, currentIndex) => (
21 |
33 | ))}
34 |
35 | {children.map((child, currentIndex) => {
36 | return (
37 |
43 | {child}
44 |
45 | )
46 | })}
47 |
48 | )
49 | }
50 |
51 | export default TabGroup
52 |
--------------------------------------------------------------------------------
/origin-src/components/Toggle.module.css:
--------------------------------------------------------------------------------
1 | /* The toggle - the box around the slider */
2 | .toggle {
3 | position: relative;
4 | display: inline-block;
5 | width: 40px;
6 | height: 26px;
7 | z-index: 1;
8 | margin-right: 12px;
9 | }
10 |
11 | /* Hide default HTML checkbox */
12 | .toggle input {
13 | opacity: 0;
14 | width: 0;
15 | height: 0;
16 | }
17 |
18 | /* The slider */
19 | .slider {
20 | position: absolute;
21 | cursor: pointer;
22 | top: 0;
23 | left: 0;
24 | right: 0;
25 | bottom: 0;
26 | background-color: white;
27 | -webkit-transition: 0.2s;
28 | transition: 0.2s;
29 | border: 1px solid transparent;
30 | }
31 |
32 | .slider:before {
33 | position: absolute;
34 | content: "";
35 | top: 1px;
36 | height: 22px;
37 | width: 20px;
38 | left: 2px;
39 | bottom: 4px;
40 | background-color: var(--color-blue);
41 | -webkit-transition: 0.2s;
42 | transition: 0.2s;
43 | }
44 |
45 | input:checked + .slider {
46 | background-color: var(--color-light-blue);
47 | }
48 |
49 | input:checked + .slider:before {
50 | background: white;
51 | }
52 |
53 | input:focus + .slider {
54 | border: 1px solid var(--color-light-pink);
55 | }
56 |
57 | input:checked + .slider:before {
58 | -webkit-transform: translateX(14px);
59 | -ms-transform: translateX(14px);
60 | transform: translateX(14px);
61 | }
62 |
63 | /* Rounded sliders */
64 | .slider.round {
65 | border-radius: 30px;
66 | }
67 |
68 | .slider.round:before {
69 | border-radius: 50%;
70 | }
71 |
--------------------------------------------------------------------------------
/origin-src/components/Toggle.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties, useEffect, useState } from "react"
2 | import styles from "./Toggle.module.css"
3 | import { useTheme } from "next-themes"
4 |
5 | export default function Toggle({ style }: { style?: CSSProperties }) {
6 | const [mounted, setMounted] = useState(false)
7 |
8 | const { theme, setTheme } = useTheme()
9 | const lightMode = theme === "light"
10 |
11 | // useEffect only runs on the client, so now we can safely show the UI
12 | useEffect(() => {
13 | setMounted(true)
14 | }, [])
15 |
16 | if (!mounted) {
17 | return null
18 | }
19 |
20 | return (
21 | // eslint-disable-next-line jsx-a11y/label-has-associated-control
22 |
37 | )
38 | }
39 |
--------------------------------------------------------------------------------
/origin-src/components/TypeText.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from "react"
2 | import typographyStyles from "../styles/typography.module.css"
3 |
4 | const TypeText = ({
5 | children,
6 | pre = false,
7 | }: {
8 | children: ReactNode
9 | pre: boolean
10 | }) => {
11 | const Element = pre ? "pre" : "span"
12 | return {children}
13 | }
14 |
15 | export default TypeText
16 |
--------------------------------------------------------------------------------
/origin-src/components/UseController.tsx:
--------------------------------------------------------------------------------
1 | import typographyStyles from "../styles/typography.module.css"
2 | import Footer from "./Footer"
3 | import containerStyles from "../styles/container.module.css"
4 | import UseControllerContent from "./UseControllerContent"
5 | import StarRepo from "./StarRepo"
6 | import { Menu, apiLinks } from "./Menu"
7 |
8 | export default function UseController() {
9 | return (
10 |
11 |
12 | useController
13 |
14 |
15 | React hooks for controlled component
16 |
17 |
18 |
19 |
20 |
21 |
22 |
27 |
28 |
29 |
30 |
31 |
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/origin-src/components/UseFieldArray.tsx:
--------------------------------------------------------------------------------
1 | import typographyStyles from "../styles/typography.module.css"
2 | import Footer from "./Footer"
3 | import containerStyles from "../styles/container.module.css"
4 | import UseFieldArrayContent from "./UseFieldArrayContent"
5 | import StarRepo from "./StarRepo"
6 | import { Menu, apiLinks } from "./Menu"
7 |
8 | export default function UseFieldArray() {
9 | return (
10 |
11 |
12 | useFieldArray
13 |
14 |
React hooks for Field Array
15 |
16 |
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/origin-src/components/Watcher.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | display: none;
3 | }
4 |
5 | .svgWrapper {
6 | width: 200px;
7 | }
8 |
9 | .watchGroup {
10 | display: flex;
11 | height: 50px;
12 | }
13 |
14 | .watchGroup p {
15 | margin-top: 5px;
16 | padding: 0 0 0 50px;
17 | }
18 |
19 | .watchGroup input[type="checkbox"] {
20 | width: 20px;
21 | margin-top: 8px;
22 | margin-left: -60px;
23 | height: 20px;
24 | background: var(--color-background);
25 | border: 1px solid var(--color-secondary);
26 | border-radius: 2px;
27 | }
28 |
29 | .watchGroup input[type="checkbox"]:checked {
30 | border: 1px solid white;
31 | background: var(--color-primary);
32 | min-width: 20px;
33 | }
34 |
35 | .svgWrapper svg {
36 | width: 100%;
37 | }
38 |
39 | .svgWrapper svg path {
40 | stroke-dasharray: 10;
41 | animation: dash 10s linear normal infinite;
42 | }
43 |
44 | .behind {
45 | background: var(--color-background);
46 | }
47 |
48 | .closed {
49 | color: var(--color-background);
50 | }
51 |
52 | @keyframes dash {
53 | from {
54 | stroke-dashoffset: 500;
55 | }
56 | to {
57 | stroke-dashoffset: 0;
58 | }
59 | }
60 |
61 | @media (min-width: 768px) {
62 | .watcher {
63 | display: block;
64 | }
65 |
66 | .root {
67 | display: grid;
68 | margin: 40px auto;
69 | max-width: 800px;
70 | grid-template-columns: 1fr 1fr 200px;
71 | }
72 |
73 | .svgWrapper {
74 | display: block;
75 | width: 300px;
76 | }
77 |
78 | .svgWrapper svg {
79 | height: 200px;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/dependantFieldsTS.tsx:
--------------------------------------------------------------------------------
1 | export default `import * as React from "react";
2 | import { useForm } from "react-hook-form";
3 |
4 | type FormValues = {
5 | a: string;
6 | b: string;
7 | c: string;
8 | };
9 |
10 | export default function App() {
11 | const { watch, register, handleSubmit, setValue, formState } = useForm<
12 | FormValues
13 | >({
14 | defaultValues: {
15 | a: "",
16 | b: "",
17 | c: ""
18 | }
19 | });
20 | const onSubmit = (data: FormValues) => console.log(data);
21 | const [a, b] = watch(["a", "b"]);
22 |
23 | React.useEffect(() => {
24 | if (formState.touchedFields.a && formState.touchedFields.b && a && b) {
25 | setValue("c", \`\${a} \${b}\`);
26 | }
27 | }, [setValue, a, b, formState]);
28 |
29 | return (
30 |
46 | );
47 | }
48 | `
49 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/devTool.tsx:
--------------------------------------------------------------------------------
1 | export default `import { useForm } from "react-hook-form";
2 | import { DevTool } from "@hookform/devtools";
3 |
4 | export default () => {
5 | const { register, control, handleSubmit } = useForm({
6 | mode: "onChange",
7 | });
8 |
9 | return (
10 | <>
11 |
19 |
20 | {/* set up the dev tool */}
21 | >
22 | );
23 | };
24 | `
25 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/formState.ts:
--------------------------------------------------------------------------------
1 | export default `import React from "react";
2 | import { useForm } from "react-hook-form";
3 |
4 | export default function App() {
5 | const {
6 | register,
7 | handleSubmit,
8 | // Read the formState before render to subscribe the form state through the Proxy
9 | formState: { errors, isDirty, isSubmitting, touchedFields, submitCount },
10 | } = useForm();
11 | const onSubmit = (data) => console.log(data);
12 |
13 | return (
14 |
18 | );
19 | }
20 | `
21 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/formStateTs.ts:
--------------------------------------------------------------------------------
1 | export default `import { useForm } from "react-hook-form";
2 |
3 | type FormInputs = {
4 | test: string
5 | }
6 |
7 | export default function App() {
8 | const {
9 | register,
10 | handleSubmit,
11 | // Read the formState before render to subscribe the form state through Proxy
12 | formState: { errors, isDirty, isSubmitting, touchedFields, submitCount },
13 | } = useForm();
14 | const onSubmit = (data: FormInputs) => console.log(data);
15 |
16 | return (
17 |
21 | );
22 | }
23 | `
24 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/formStateUseEffect.ts:
--------------------------------------------------------------------------------
1 | export default `import { useForm } from "react-hook-form";
2 |
3 | export default function App () {
4 | const {
5 | register,
6 | handleSubmit,
7 | formState
8 | } = useForm();
9 |
10 | const onSubmit = (data) => console.log(data);
11 |
12 | React.useEffect(() => {
13 | console.log("touchedFields", formState.touchedFields);
14 | },[formState]); // use entire formState object as optional array arg in useEffect, not individual properties of it
15 |
16 |
17 | return (
18 |
22 | );
23 | };
24 |
25 | `
26 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/formStateUseEffectTs.ts:
--------------------------------------------------------------------------------
1 | export default `import React from "react";
2 | import { useForm } from "react-hook-form";
3 | type FormInputs = {
4 | test: string
5 | }
6 | export default function App() {
7 | const {
8 | register,
9 | handleSubmit,
10 | formState
11 | } = useForm();
12 | const onSubmit = (data: FormInputs) => console.log(data);
13 |
14 | React.useEffect(() => {
15 | console.log("touchedFields", formState.touchedFields);
16 | }, [formState]);
17 |
18 | return (
19 |
23 | );
24 | }
25 | `
26 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/reactHookFormCode.ts:
--------------------------------------------------------------------------------
1 | export default `import { useForm } from "react-hook-form";
2 |
3 | const Example = () => {
4 | const { handleSubmit, register, formState: { errors } } = useForm();
5 | const onSubmit = values => console.log(values);
6 |
7 | return (
8 |
30 | );
31 | };
32 | `
33 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/useController.ts:
--------------------------------------------------------------------------------
1 | export default `import { TextField } from "@material-ui/core";
2 | import { useController, useForm } from "react-hook-form";
3 |
4 | function Input({ control, name }) {
5 | const {
6 | field,
7 | fieldState: { invalid, isTouched, isDirty },
8 | formState: { touchedFields, dirtyFields }
9 | } = useController({
10 | name,
11 | control,
12 | rules: { required: true },
13 | });
14 |
15 | return (
16 |
23 | );
24 | }
25 | `
26 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/useControllerTs.ts:
--------------------------------------------------------------------------------
1 | export default `import * as React from "react";
2 | import { useForm, useController, UseControllerProps } from "react-hook-form";
3 |
4 | type FormValues = {
5 | FirstName: string;
6 | };
7 |
8 | function Input(props: UseControllerProps) {
9 | const { field, fieldState } = useController(props);
10 |
11 | return (
12 |
13 |
14 |
{fieldState.isTouched && "Touched"}
15 |
{fieldState.isDirty && "Dirty"}
16 |
{fieldState.invalid ? "invalid" : "valid"}
17 |
18 | );
19 | }
20 |
21 | export default function App() {
22 | const { handleSubmit, control } = useForm({
23 | defaultValues: {
24 | FirstName: ""
25 | },
26 | mode: "onChange"
27 | });
28 | const onSubmit = (data: FormValues) => console.log(data);
29 |
30 | return (
31 |
35 | );
36 | }
37 | `
38 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/useFieldArray.ts:
--------------------------------------------------------------------------------
1 | export default `import React from "react";
2 | import { useForm, useFieldArray } from "react-hook-form";
3 |
4 | function App() {
5 | const { register, control, handleSubmit, reset, trigger, setError } = useForm({
6 | // defaultValues: {}; you can populate the fields by this attribute
7 | });
8 | const { fields, append, remove } = useFieldArray({
9 | control,
10 | name: "test"
11 | });
12 |
13 | return (
14 |
36 | );
37 | }
38 | `
39 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/useFieldArrayArgument.ts:
--------------------------------------------------------------------------------
1 | export default `function FieldArray() {
2 | const { control, register } = useForm();
3 | const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({
4 | control, // control props comes from useForm (optional: if you are using FormProvider)
5 | name: "test", // unique name for your Field Array
6 | });
7 |
8 | return (
9 | {fields.map((field, index) => (
10 |
14 | ))}
15 | );
16 | }
17 |
18 | `
19 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/useFieldArrayConditional.ts:
--------------------------------------------------------------------------------
1 | export default `import React from 'react';
2 | import { useForm, useWatch, useFieldArray, Control } from 'react-hook-form';
3 |
4 | type FormValues = {
5 | data: { name: string }[];
6 | };
7 |
8 | const ConditionField = ({
9 | control,
10 | index,
11 | register,
12 | }: {
13 | control: Control;
14 | index: number;
15 | }) => {
16 | const output = useWatch({
17 | name: 'data',
18 | control,
19 | defaultValue: 'yay! I am watching you :)',
20 | });
21 |
22 | return (
23 | <>
24 | {output[index]?.name === "bill" && (
25 |
26 | )}
27 |
31 | >
32 | );
33 | };
34 |
35 | const UseFieldArrayUnregister: React.FC = () => {
36 | const { control, handleSubmit, register } = useForm({
37 | defaultValues: {
38 | data: [{ name: 'test' }, { name: 'test1' }, { name: 'test2' }],
39 | },
40 | mode: 'onSubmit',
41 | shouldUnregister: false,
42 | });
43 | const { fields } = useFieldArray({
44 | control,
45 | name: 'data',
46 | });
47 | const onSubmit = (data: FormValues) => console.log(data);
48 |
49 | return (
50 |
59 | );
60 | };
61 | `
62 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/useFieldArrayFocus.ts:
--------------------------------------------------------------------------------
1 | export default `import React from 'react';
2 | import { useForm, useFieldArray } from 'react-hook-form';
3 |
4 | const App = () => {
5 | const { register, control } = useForm<{
6 | test: { value: string }[];
7 | }>({
8 | defaultValues: {
9 | test: [{ value: '1' }, { value: '2' }],
10 | },
11 | });
12 | const { fields, prepend, append } = useFieldArray({
13 | name: 'test',
14 | control,
15 | });
16 |
17 | return (
18 |
35 | );
36 | };
37 | `
38 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/useFieldArrayPreview.ts:
--------------------------------------------------------------------------------
1 | export default `import * as React from "react";
2 | import { useForm, useFieldArray, useWatch } from "react-hook-form";
3 |
4 | export default function App() {
5 | const { control, handleSubmit } = useForm();
6 | const { fields, append, update } = useFieldArray({
7 | control,
8 | name: 'array'
9 | });
10 |
11 | return (
12 |
33 | );
34 | }
35 |
36 | const Display = ({ control, index }) => {
37 | const data = useWatch({
38 | control,
39 | name: \`array.\${index}\`
40 | });
41 | return {data?.firstName}
;
42 | };
43 |
44 | const Edit = ({ update, index, value, control }) => {
45 | const { register, handleSubmit } = useForm({
46 | defaultValues: value
47 | });
48 |
49 | return (
50 |
51 |
52 |
53 |
57 |
58 |
64 |
65 | );
66 | };
67 |
68 | `
69 |
--------------------------------------------------------------------------------
/origin-src/components/codeExamples/useFormState.ts:
--------------------------------------------------------------------------------
1 | export default `import * as React from "react";
2 | import { useForm, useFormState } from "react-hook-form";
3 |
4 | function Child({ control }) {
5 | const { dirtyFields } = useFormState({
6 | control
7 | });
8 |
9 | return dirtyFields.firstName ? Field is dirty.
: null;
10 | };
11 |
12 | export default function App() {
13 | const { register, handleSubmit, control } = useForm({
14 | defaultValues: {
15 | firstName: "firstName"
16 | }
17 | });
18 | const onSubmit = (data) => console.log(data);
19 |
20 | return (
21 |
27 | );
28 | }
29 | `
30 |
--------------------------------------------------------------------------------
/origin-src/components/general-observer.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FunctionComponent,
3 | RefObject,
4 | useEffect,
5 | useRef,
6 | useState,
7 | ReactNode,
8 | } from "react"
9 |
10 | interface IGeneralObserverProps {
11 | /** React Children */
12 | children: ReactNode
13 | placeholder?: ReactNode
14 | /** Fires when IntersectionObserver enters viewport */
15 | onEnter?: (id?: string) => void
16 | }
17 |
18 | export const GeneralObserver: FunctionComponent = ({
19 | children,
20 | onEnter,
21 | placeholder,
22 | }) => {
23 | const ref = useRef(null)
24 | const [isChildVisible, setIsChildVisible] = useState(false)
25 |
26 | useEffect(() => {
27 | const observer = new IntersectionObserver(
28 | ([entry]) => {
29 | if (entry.isIntersecting) {
30 | setIsChildVisible(true)
31 | onEnter?.()
32 | }
33 | },
34 | {
35 | rootMargin: "0px 0px",
36 | threshold: [1],
37 | }
38 | )
39 | if (ref.current) {
40 | observer.observe(ref.current)
41 | }
42 |
43 | return () => {
44 | observer.disconnect()
45 | }
46 | }, [ref, onEnter])
47 |
48 | let slot = children
49 |
50 | if (placeholder && isChildVisible) {
51 | slot = placeholder
52 | }
53 |
54 | return (
55 | } data-testid="general-observer">
56 | {slot}
57 |
58 | )
59 | }
60 |
--------------------------------------------------------------------------------
/origin-src/components/learnMore.tsx:
--------------------------------------------------------------------------------
1 | import generic from "../data/generic"
2 | import containerStyles from "../styles/container.module.css"
3 | import buttonStyles from "../styles/button.module.css"
4 | import { useRouter } from "next/router"
5 |
6 | export default function LearnMore() {
7 | const router = useRouter()
8 | return (
9 |
10 |
{generic.learnMore.title}
11 |
{generic.learnMore.description}
12 |
13 |
22 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/origin-src/components/logic/getEditLink.tsx:
--------------------------------------------------------------------------------
1 | const preFix =
2 | "https://github.com/react-hook-form/documentation/edit/master/src/"
3 |
4 | const dataPreFix = "data/"
5 | const pagesPreFix = "pages/"
6 | const content = "content/"
7 |
8 | const filterApiPageURL = (pathname: string): string => {
9 | if (pathname.charAt(pathname.length - 1) === "/")
10 | return pathname.substring(0, pathname.length - 1).substring(1)
11 |
12 | return pathname.substring(1)
13 | }
14 |
15 | export const getEditLink = (pathname: string): string => {
16 | if (!pathname) return ""
17 |
18 | if (pathname === "/" || pathname === "") {
19 | return `${preFix}${dataPreFix}/home.tsx`
20 | } else if (pathname.includes("get-started")) {
21 | return `${preFix}${content}get-started.mdx`
22 | } else if (pathname.includes("api")) {
23 | const splitPath = pathname.split("/")
24 | if (splitPath.length === 2 || splitPath[2] === "") {
25 | return `${preFix}${dataPreFix}api.tsx`
26 | }
27 | return `${preFix}${pagesPreFix}${filterApiPageURL(pathname)}.tsx`
28 | } else if (pathname.includes("ts")) {
29 | return `${preFix}${content}ts.mdx`
30 | } else if (pathname.includes("advanced-usage")) {
31 | return `${preFix}${content}advanced.mdx`
32 | } else if (pathname.includes("faqs")) {
33 | return `${preFix}${content}faq.mdx`
34 | } else if (pathname.includes("dev-tools")) {
35 | return `${preFix}${dataPreFix}devtools.tsx`
36 | } else if (pathname.includes("form-builder")) {
37 | return `${preFix}${dataPreFix}builder.tsx`
38 | } else if (pathname.includes("resources")) {
39 | return `${preFix}${dataPreFix}resources.tsx`
40 | }
41 |
42 | return ""
43 | }
44 |
--------------------------------------------------------------------------------
/origin-src/components/mdx/code.tsx:
--------------------------------------------------------------------------------
1 | import { useMemo } from "react"
2 | import type { ReactNode } from "react"
3 | import { Highlight } from "prism-react-renderer"
4 | import { useTheme } from "next-themes"
5 | import { darkTheme, lightTheme } from "./theme"
6 |
7 | function usePrismTheme() {
8 | const { theme } = useTheme()
9 |
10 | return useMemo(() => {
11 | if (theme === "light") return lightTheme
12 | return darkTheme
13 | }, [theme])
14 | }
15 |
16 | export const PrismSyntaxHighlight = ({
17 | children,
18 | className,
19 | }: {
20 | children: ReactNode
21 | className: string
22 | }) => {
23 | const language = className.replace(/language-/gm, "")
24 |
25 | const currentTheme = usePrismTheme()
26 |
27 | return (
28 |
33 | {({ className, style, tokens, getLineProps, getTokenProps }) => (
34 |
35 | {tokens.map((line, lineIndex) => {
36 | const { key: lineKey, ...lineProps } = getLineProps({
37 | line,
38 | key: lineIndex,
39 | })
40 |
41 | return (
42 |
43 | {line.map((lineToken, linenTokenIndex) => {
44 | const { key: lineTokenKey, ...lineTokenProps } =
45 | getTokenProps({
46 | token: lineToken,
47 | key: linenTokenIndex,
48 | })
49 | return (
50 |
51 | )
52 | })}
53 |
54 | )
55 | })}
56 |
57 | )}
58 |
59 | )
60 | }
61 |
--------------------------------------------------------------------------------
/origin-src/components/mdx/mdx.tsx:
--------------------------------------------------------------------------------
1 | import { PrismSyntaxHighlight } from "./code"
2 | import { Pre } from "./pre"
3 | import TabGroup from "../TabGroup"
4 | import { YouTube } from "./youtube"
5 | import TypeText from "../TypeText"
6 | import Popup from "../Popup"
7 | import { Components } from "@mdx-js/react/lib"
8 | import { Admonition } from "../Admonition"
9 | import { CodeSandBoxLink } from "../CodeSandbox"
10 | import tableStyles from "../../styles/table.module.css"
11 | import { SelectNav } from "@/components/selectNav"
12 | import CodeArea from "@/components/CodeArea"
13 |
14 | export const MDXComponents: Components = {
15 | // p: P,
16 | // strong: Strong,
17 | // blockquote: Blockquote,
18 | // ol: OL,
19 | // ul: UL,
20 | // li: LI,
21 | // h1: H1,
22 | // h2: H2,
23 | // h3: H3,
24 | // h4: H4,
25 | // hr: Divider,
26 | // a: Link,
27 | // img: ResponsiveImage,
28 | // Layout,
29 | SelectNav,
30 | CodeArea,
31 | table(props) {
32 | return (
33 |
36 | )
37 | },
38 | Admonition,
39 | Popup,
40 | TypeText,
41 | YouTube(props) {
42 | return
43 | },
44 | CodeSandbox: CodeSandBoxLink,
45 | pre(props) {
46 | return
47 | },
48 | code({ className, children, ...props }) {
49 | return className ? (
50 |
51 | {children}
52 |
53 | ) : (
54 | {children}
55 | )
56 | },
57 | TabGroup,
58 | PrettyObject({ value }: { value: Record }) {
59 | return JSON.stringify(value, null, 2).replace(/"/g, "")
60 | },
61 | }
62 |
--------------------------------------------------------------------------------
/origin-src/components/mdx/pre.tsx:
--------------------------------------------------------------------------------
1 | import type { DetailedHTMLProps, HTMLAttributes } from "react"
2 | import { isValidElement, useRef } from "react"
3 | import ClipBoard from "../ClipBoard"
4 | import styles from "../CodeArea.module.css"
5 | import copyClipBoard from "../utils/copyClipBoard"
6 | import { CodeSandBoxLink } from "../CodeSandbox"
7 |
8 | export const Pre = (
9 | props: DetailedHTMLProps, HTMLPreElement> & {
10 | copy?: boolean
11 | sandbox?: string
12 | expo?: boolean
13 | }
14 | ) => {
15 | const preRef = useRef(null)
16 |
17 | const language = isValidElement<{ className?: string }>(props.children)
18 | ? props.children.props.className?.replace(/language-/gm, "") || ""
19 | : ""
20 |
21 | const isJs = language === "javascript"
22 |
23 | return (
24 |
29 |
30 | {props.copy && (
31 | {
34 | if (preRef.current?.innerText) {
35 | copyClipBoard(preRef.current.innerText)
36 | }
37 | }}
38 | />
39 | )}
40 | {props.sandbox && (
41 |
46 | )}
47 |
48 |
{props.children}
49 |
50 | )
51 | }
52 |
--------------------------------------------------------------------------------
/origin-src/components/mdx/youtube.tsx:
--------------------------------------------------------------------------------
1 | import { FunctionComponent } from "react"
2 |
3 | import { GeneralObserver } from "../general-observer"
4 |
5 | interface YouTubeProps {
6 | /** YouTube id */
7 | youTubeId: string
8 |
9 | /** Auto play the video */
10 | autoPlay?: boolean
11 |
12 | /** No Cookie option */
13 | noCookie?: boolean
14 | }
15 |
16 | export const YouTube: FunctionComponent = (
17 | props: YouTubeProps
18 | ) => {
19 | const { youTubeId, autoPlay = false, noCookie = false } = props
20 |
21 | const provider = noCookie
22 | ? "https://www.youtube-nocookie.com"
23 | : "https://www.youtube.com"
24 |
25 | const src = `${provider}/embed/${youTubeId}?&autoplay=${autoPlay.toString()}`
26 |
27 | return (
28 |
29 |
39 |
40 | )
41 | }
42 |
--------------------------------------------------------------------------------
/origin-src/components/selectNav.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100%;
3 | margin-top: 1rem;
4 | background: none;
5 | appearance: none;
6 | color: var(--color-text);
7 | border: 1px solid var(--color-light-blue);
8 | border-radius: 3px;
9 | padding-left: 15px;
10 | padding-right: 15px;
11 | cursor: pointer;
12 | position: relative;
13 | }
14 |
15 | .root:hover {
16 | border: 1px solid var(--color-secondary);
17 | }
18 |
19 | .root > option {
20 | color: black;
21 | }
22 |
23 | @media (min-width: 768px) {
24 | .root {
25 | display: none;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/origin-src/components/selectNav.tsx:
--------------------------------------------------------------------------------
1 | import styles from "./selectNav.module.css"
2 | import { useRouter } from "next/router"
3 |
4 | type Props = {
5 | options: {
6 | value: string
7 | label: string
8 | }[]
9 | }
10 |
11 | export function SelectNav({ options }: Props) {
12 | const router = useRouter()
13 |
14 | return (
15 | // eslint-disable-next-line jsx-a11y/no-onchange
16 |
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/origin-src/components/seo.tsx:
--------------------------------------------------------------------------------
1 | import Head from "next/head"
2 |
3 | const site = {
4 | siteMetadata: {
5 | title: `React Hook Form - Simple React forms validation`,
6 | description: `Performant, flexible and extensible forms with easy-to-use validation.`,
7 | author: `@bluebill1049`,
8 | siteUrl: "https://www.react-hook-form.com",
9 | languages: {
10 | langs: ["en", "es", "jp", "zh", "kr", "pt", "ru"],
11 | defaultLangKey: "en",
12 | },
13 | },
14 | }
15 |
16 | function SEO({ title, description }: { title: string; description?: string }) {
17 | const metaDescription = description || site.siteMetadata.description
18 |
19 | return (
20 |
21 | {title || site.siteMetadata.title}
22 |
27 |
31 |
32 |
36 |
37 |
38 |
42 |
46 |
47 | )
48 | }
49 |
50 | export default SEO
51 |
--------------------------------------------------------------------------------
/origin-src/components/sponsorsList.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | text-align: center;
3 | margin: 1rem 0 1rem 0;
4 | font-size: 0.8rem;
5 | border-top: 1px solid var(--color-black);
6 | padding-top: 1.5rem;
7 | }
8 |
9 | .heading {
10 | margin-bottom: 2rem;
11 | opacity: 0.7;
12 | font-weight: 500;
13 | }
14 |
15 | .root a {
16 | color: white;
17 | text-decoration: none;
18 | display: flex;
19 | align-content: center;
20 | justify-content: center;
21 | }
22 |
23 | .root a img {
24 | width: 120px;
25 | height: auto;
26 | margin: auto 0;
27 | }
28 |
29 | .logoGroup {
30 | display: grid;
31 | grid-template-columns: repeat(2, 1fr);
32 | gap: 1rem;
33 | margin: 0 1rem;
34 | }
35 |
36 | .logoGroup > div {
37 | border-radius: 4px;
38 | padding: 0.5rem;
39 | }
40 |
41 | .placeholder {
42 | border: 1px dashed #ccc;
43 | border-radius: 4px;
44 | padding: 0.5rem;
45 | }
46 |
47 | .twicsy {
48 | border-radius: 50px;
49 | }
50 |
51 | @media (min-width: 768px) {
52 | .logoGroup {
53 | display: grid;
54 | max-width: 600px;
55 | margin: 0 auto;
56 | grid-template-columns: repeat(4, 1fr);
57 | gap: 1.5rem;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/origin-src/components/sponsorsList.tsx:
--------------------------------------------------------------------------------
1 | import styles from "./sponsorsList.module.css"
2 |
3 | export function SponsorsList() {
4 | return (
5 |
6 |
SUPPORTED AND BACKED BY
7 |
8 |
52 |
53 | )
54 | }
55 |
--------------------------------------------------------------------------------
/origin-src/components/utils/copyClipBoard.ts:
--------------------------------------------------------------------------------
1 | export default function copyToClipboard(text: string) {
2 | return new Promise((resolve, reject) => {
3 | if (navigator?.clipboard) {
4 | const cb = navigator.clipboard
5 | cb.writeText(text).then(resolve).catch(reject)
6 | } else {
7 | try {
8 | const body = document.querySelector("body")
9 |
10 | const textarea = document.createElement("textarea")
11 | body?.appendChild(textarea)
12 |
13 | textarea.value = text
14 | textarea.select()
15 |
16 | document.execCommand("copy")
17 |
18 | body?.removeChild(textarea)
19 |
20 | resolve(0)
21 | } catch (e) {
22 | reject(e as Error)
23 | }
24 | }
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/origin-src/components/utils/goToBuilder.ts:
--------------------------------------------------------------------------------
1 | export default function goToBuilder(toggle = true) {
2 | const title = " | React hook form - Simple React form validation"
3 |
4 | if (toggle) {
5 | document.title = `Form Builder${title}`
6 | window.history.pushState(
7 | { page: `Form Builder${title}` },
8 | `Form Builder${title}`,
9 | `/form-builder`
10 | )
11 | } else {
12 | document.title = `Home${title}`
13 | window.history.pushState({ page: `Home${title}` }, `Home${title}`, `/`)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/origin-src/components/utils/useWindowSize.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react"
2 |
3 | interface Size {
4 | width: number
5 | height: number
6 | }
7 |
8 | export default function useWindowSize(): Size {
9 | const [windowSize, setWindowSize] = useState({
10 | width: 0,
11 | height: 0,
12 | })
13 |
14 | useEffect(() => {
15 | function handleResize() {
16 | setWindowSize({
17 | width: window.innerWidth,
18 | height: window.innerHeight,
19 | })
20 | }
21 |
22 | window.addEventListener("resize", handleResize)
23 |
24 | return () => {
25 | window.removeEventListener("resize", handleResize)
26 | }
27 | }, [])
28 |
29 | return windowSize
30 | }
31 |
--------------------------------------------------------------------------------
/origin-src/content/docs/formprovider.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: FormProvider
3 | description: A component to provide React Context
4 | sidebar: apiLinks
5 | ---
6 |
7 | This component will host context object and allow consuming component to subscribe to context and use [useForm](/docs/useform) props and methods.
8 |
9 | ### Props
10 |
11 | ---
12 |
13 | This following table applied to `FormProvider`, `useFormContext` accepts no argument.
14 |
15 | | Name | Type | Description |
16 | | ---------- | --------------------------- | ---------------------------------------------- |
17 | | `...props` | Object | `FormProvider` requires all `useForm` methods. |
18 |
19 |
20 |
21 | - Avoid using nested FormProvider
22 |
23 |
24 |
25 | **Examples:**
26 |
27 | ---
28 |
29 | ```javascript copy sandbox="https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi"
30 | import React from "react"
31 |
32 | import { useForm, FormProvider, useFormContext } from "react-hook-form"
33 |
34 | export default function App() {
35 | const methods = useForm()
36 |
37 | const onSubmit = (data) => console.log(data)
38 | const { register, reset } = methods
39 |
40 | useEffect(() => {
41 | reset({
42 | name: "data",
43 | })
44 | }, [reset]) // ❌ never put `methods` as the deps
45 |
46 | return (
47 |
48 | // pass all methods into the context
49 |
54 |
55 | )
56 | }
57 |
58 | function NestedInput() {
59 | const { register } = useFormContext() // retrieve all hook methods
60 |
61 | return
62 | }
63 | ```
64 |
--------------------------------------------------------------------------------
/origin-src/content/docs/useform/control.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: control
3 | description: Take control of the form
4 | sidebar: apiLinks
5 | ---
6 |
7 | ## \> `control:` Object
8 |
9 | This object contains methods for registering components into React Hook Form.
10 |
11 |
12 |
13 | **Important:** do not access any of the properties inside this object directly. It's for internal usage only.
14 |
15 |
16 |
17 | **Examples:**
18 |
19 | ---
20 |
21 |
22 |
23 | ```typescript copy sandbox="https://codesandbox.io/s/react-hook-form-v6-controller-ts-jwyzw"
24 | import React from "react"
25 | import { useForm, Controller } from "react-hook-form"
26 | import { TextField } from "@material-ui/core"
27 |
28 | type FormInputs = {
29 | firstName: string
30 | }
31 |
32 | function App() {
33 | const { control, handleSubmit } = useForm()
34 | const onSubmit = (data: FormInputs) => console.log(data)
35 |
36 | return (
37 |
47 | )
48 | }
49 | ```
50 |
51 | ```javascript copy sandbox="https://codesandbox.io/s/react-hook-form-v7-controller-5h1q5"
52 | import { useForm, Controller } from "react-hook-form"
53 |
54 | function App() {
55 | const { control } = useForm()
56 |
57 | return (
58 | }
60 | name="firstName"
61 | control={control}
62 | defaultValue=""
63 | />
64 | )
65 | }
66 | ```
67 |
68 |
69 |
--------------------------------------------------------------------------------
/origin-src/data/builder.tsx:
--------------------------------------------------------------------------------
1 | export default {
2 | title: "Form Builder",
3 | description: "GUI for building forms with validation",
4 | builder: {
5 | title: "Form Builder",
6 | description: "Build your form with code and example.",
7 | },
8 | layout: {
9 | title: "Layout",
10 | message: "You can start adding fields with Input Creator.",
11 | },
12 | inputCreator: {
13 | title: "Input Creator",
14 | description: `This form allows you to create and update inputs. The Generate Form button will create a new form with the updates.`,
15 | message: "You can start adding fields with Input Creator.",
16 | options: "Options",
17 | validation: "Show validation",
18 | generate: "Generate Form",
19 | },
20 | code: {
21 | title: "Code",
22 | description: `As you are making changes over the form, the code section will be updated and you can copy the code as well.`,
23 | },
24 | }
25 |
--------------------------------------------------------------------------------
/origin-src/data/generic.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link"
2 |
3 | export default {
4 | copy: "Copy",
5 | codeCopied: "Copied",
6 | required: "Required",
7 | learnMore: {
8 | title: "Want to learn more?",
9 | description:
10 | "Check out the React Hook Form documentation and learn all about the API.",
11 | buttonText: "Checkout API",
12 | },
13 | advanceUsage: {
14 | title: "Advanced Usage",
15 | description: `Learn how to build complex and accessible forms`,
16 | buttonText: `Learn Advanced Usage`,
17 | },
18 | needYourSupport: {
19 | title: "Thank you for your support",
20 | description: `If you find React Hook Form to be useful in your project, please consider to star and support it.`,
21 | buttonText: `Star us on GitHub`,
22 | },
23 | codeExample: "Code Examples",
24 | menu: "Menu",
25 | note: "Note",
26 | select: "Select",
27 | name: "Name",
28 | type: "Type",
29 | default: "Default",
30 | description: "Description",
31 | features: "Features",
32 | delete: "Delete",
33 | example: "Example",
34 | edit: "Edit",
35 | cancelEdit: "Cancel Edit",
36 | reset: "Reset",
37 | deleteAll: "Delete All",
38 | create: "Create",
39 | update: "Update",
40 | copied: "Copy code into your clipboard.",
41 | return: "Return",
42 | blog: "Articles/Blog",
43 | video: "Videos",
44 | newsletter: "Newsletter",
45 | binding: "3rd Party Bindings",
46 | liveDemo: "Live Demo",
47 | control: (
48 | <>
49 |
50 | control
51 | {" "}
52 | object provided by useForm
. It's optional if you are using
53 | FormProvider.
54 | >
55 | ),
56 | }
57 |
--------------------------------------------------------------------------------
/origin-src/data/nav.tsx:
--------------------------------------------------------------------------------
1 | const Nav = {
2 | home: "Home",
3 | getStarted: "Get Started",
4 | advanced: "Advanced",
5 | tools: {
6 | nav: "Tools",
7 | devTools: "DevTools",
8 | formBuilder: "Form Builder",
9 | },
10 | builder: (
11 | <>
12 | Form Builder
13 | >
14 | ),
15 | faqs: "FAQs",
16 | releases: "Releases",
17 | resources: "Resources",
18 | }
19 |
20 | export default Nav
21 |
--------------------------------------------------------------------------------
/origin-src/pages/404.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | padding: 2rem;
3 | }
4 |
5 | .root {
6 | text-align: center;
7 | }
8 |
--------------------------------------------------------------------------------
/origin-src/pages/404.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../components/layout"
2 | import Seo from "../components/seo"
3 | import styles from "./404.module.css"
4 |
5 | const NotFoundPage = () => (
6 |
7 |
8 |
9 |
10 | NOT FOUND
11 | You just found a route that doesn't exist... the sadness.
12 |
13 |
14 |
15 | )
16 |
17 | export default NotFoundPage
18 |
--------------------------------------------------------------------------------
/origin-src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import { StateMachineProvider, createStore } from "little-state-machine"
2 | import { type AppProps } from "next/app"
3 | import Head from "next/head"
4 | import formData from "../state/formData"
5 | import { ThemeProvider } from "next-themes"
6 | import { useEffect } from "react"
7 | import "../components/layout.css"
8 |
9 | createStore(
10 | {
11 | formData,
12 | },
13 | {
14 | storageType:
15 | typeof window !== "undefined" ? window.localStorage : undefined,
16 | }
17 | )
18 |
19 | function App({ Component, pageProps }: AppProps) {
20 | useEffect(() => {
21 | try {
22 | if ("serviceWorker" in window.navigator) {
23 | navigator.serviceWorker.getRegistrations().then((registrations) => {
24 | if (Array.isArray(registrations)) {
25 | for (const registration of registrations) {
26 | ;(registration as ServiceWorkerRegistration).unregister()
27 | }
28 | }
29 | })
30 | }
31 | } catch {}
32 | }, [])
33 |
34 | return (
35 | <>
36 |
37 | React Hook Form - Simple React forms validation
38 |
42 |
43 |
48 |
49 |
50 |
51 |
52 | >
53 | )
54 | }
55 |
56 | export default App
57 |
--------------------------------------------------------------------------------
/origin-src/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from "next/document"
2 | import Script from "next/script"
3 |
4 | export default function Document() {
5 | return (
6 |
7 |
8 |
12 |
16 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/origin-src/pages/dev-tools.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../components/layout"
2 | import Seo from "../components/seo"
3 | import DevTools from "../components/DevTools"
4 | import api from "../data/api"
5 |
6 | const Api = () => (
7 |
8 |
9 |
10 |
11 | )
12 |
13 | export default Api
14 |
--------------------------------------------------------------------------------
/origin-src/pages/docs.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../components/layout"
2 | import Seo from "../components/seo"
3 | import api from "../data/api"
4 | import ApiGallery from "../components/ApiGallery"
5 |
6 | const Api = () => (
7 |
8 |
9 |
10 |
11 | )
12 |
13 | export default Api
14 |
--------------------------------------------------------------------------------
/origin-src/pages/docs/usecontroller.tsx:
--------------------------------------------------------------------------------
1 | import Seo from "../../components/seo"
2 | import Layout from "../../components/layout"
3 | import UseControllerContent from "../../components/UseController"
4 |
5 | export default function Usecontroller() {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/origin-src/pages/docs/usefieldarray.tsx:
--------------------------------------------------------------------------------
1 | import Seo from "../../components/seo"
2 | import Layout from "../../components/layout"
3 | import UseFieldArrayContent from "../../components/UseFieldArray"
4 |
5 | export default function UseFieldArray() {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/origin-src/pages/form-builder.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../components/layout"
2 | import Seo from "../components/seo"
3 | import BuilderPage from "../components/BuilderPage"
4 | import builder from "../data/builder"
5 |
6 | const Api = () => {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
15 | export default Api
16 |
--------------------------------------------------------------------------------
/origin-src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../components/layout"
2 | import Seo from "../components/seo"
3 | import Home from "../components/HomePage"
4 | import home from "../data/home"
5 |
6 | const IndexPage = () => (
7 |
8 |
9 |
10 |
11 | )
12 |
13 | export default IndexPage
14 |
--------------------------------------------------------------------------------
/origin-src/pages/media.module.css:
--------------------------------------------------------------------------------
1 | .media {
2 | max-width: 800px;
3 | margin: 3rem auto;
4 | display: flex;
5 | flex-direction: column;
6 | grid-template-columns: 1fr 1fr;
7 | gap: 2rem;
8 | }
9 |
10 | .media div {
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | }
15 |
16 | .media p {
17 | font-size: 12px;
18 | }
19 |
20 | .media img {
21 | width: 100%;
22 | border-radius: 10px;
23 | }
24 |
25 | img.logo {
26 | width: 200px;
27 | height: 200px;
28 | }
29 |
30 | @media (min-width: 768px) {
31 | .media {
32 | margin: 3rem auto;
33 | display: grid;
34 | grid-template-columns: 1fr 1fr;
35 | gap: 2rem;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/origin-src/pages/migrate-v6-to-v7.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react"
2 |
3 | export default function MigrateV6ToV7() {
4 | useEffect(() => {
5 | window.location.href = "https://legacy.react-hook-form.com/migrate-v6-to-v7"
6 | }, [])
7 |
8 | return null
9 | }
10 |
--------------------------------------------------------------------------------
/origin-src/pages/resources/3rd-party-bindings.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../../components/layout"
2 | import Seo from "../../components/seo"
3 | import ResourcePageBindings from "../../components/ResourcePageBindings"
4 |
5 | const ResourcesBindings = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default ResourcesBindings
15 |
--------------------------------------------------------------------------------
/origin-src/pages/resources/articles.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../../components/layout"
2 | import Seo from "../../components/seo"
3 | import ResourcePageArticles from "../../components/ResourcePageArticles"
4 |
5 | const ResourcesArticles = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default ResourcesArticles
15 |
--------------------------------------------------------------------------------
/origin-src/pages/resources/newsletters.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../../components/layout"
2 | import Seo from "../../components/seo"
3 | import ResourcePageNewsletter from "../../components/ResourcePageNewsletter"
4 |
5 | const ResourcesNewsletter = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default ResourcesNewsletter
15 |
--------------------------------------------------------------------------------
/origin-src/pages/resources/videos.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../../components/layout"
2 | import Seo from "../../components/seo"
3 | import ResourcePageVideos from "../../components/ResourcePageVideos"
4 |
5 | const ResourcesVideos = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default ResourcesVideos
15 |
--------------------------------------------------------------------------------
/origin-src/state/formData.ts:
--------------------------------------------------------------------------------
1 | import type { GlobalState } from "little-state-machine"
2 |
3 | const formData: GlobalState["formData"] = [
4 | {
5 | name: "First name",
6 | type: "text",
7 | required: true,
8 | max: "",
9 | min: "",
10 | maxLength: "80",
11 | minLength: "",
12 | pattern: "",
13 | },
14 | {
15 | name: "Last name",
16 | type: "text",
17 | required: true,
18 | max: "",
19 | min: "",
20 | maxLength: "100",
21 | minLength: "",
22 | pattern: "",
23 | },
24 | {
25 | name: "Email",
26 | type: "text",
27 | required: true,
28 | max: "",
29 | min: "",
30 | maxLength: "",
31 | minLength: "",
32 | pattern: "^\\S+@\\S+$",
33 | },
34 | {
35 | name: "Mobile number",
36 | type: "tel",
37 | required: true,
38 | max: "",
39 | min: "",
40 | maxLength: "12",
41 | minLength: "6",
42 | pattern: "",
43 | },
44 | {
45 | name: "Title",
46 | type: "select",
47 | required: true,
48 | max: "",
49 | min: "",
50 | maxLength: "",
51 | minLength: "",
52 | pattern: "",
53 | options: "Mr;Mrs;Miss;Dr",
54 | },
55 | {
56 | name: "Developer",
57 | type: "radio",
58 | required: true,
59 | max: "",
60 | min: "",
61 | maxLength: "",
62 | minLength: "",
63 | pattern: "",
64 | options: "Yes;No",
65 | },
66 | ]
67 |
68 | export default formData
69 |
--------------------------------------------------------------------------------
/origin-src/styles/breakpoints.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | fromXsmallScreen: "(min-width: 320px)",
3 | fromSmallScreen: "(min-width: 480px)",
4 | fromMediumScreen: "(min-width: 768px)",
5 | fromLargeScreen: "(min-width: 1024px)",
6 | fromXlargeScreen: "(min-width: 1280px)",
7 | fromXxlargeScreen: "(min-width: 1600px)",
8 | }
9 |
10 | export const LARGE_SCREEN = 1600
11 |
--------------------------------------------------------------------------------
/origin-src/styles/colors.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | primary: "#0e101c",
3 | secondary: "#bf1650",
4 | lightBlue: "#516391",
5 | blue: "#1e2a4a",
6 | lightPink: "#ec5990",
7 | errorPink: "#fbecf2",
8 | buttonBlue: "#191d3a",
9 | link: "#ff7aa8",
10 | black: "#000",
11 | }
12 |
--------------------------------------------------------------------------------
/origin-src/styles/container.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | padding-top: 45px;
3 | }
4 |
5 | .subContainer {
6 | margin: 0 auto;
7 | max-width: 768px;
8 | }
9 |
10 | .centerContent {
11 | margin: 0 auto;
12 | text-align: center;
13 | max-width: 1024px;
14 | }
15 |
16 | .centerContent svg {
17 | display: none;
18 | }
19 |
20 | .wrapper {
21 | max-width: 1235px;
22 | margin: 0 auto;
23 | overflow: hidden;
24 | position: relative;
25 | padding: 0 15px 50px 20px;
26 | }
27 |
28 | .centerContent p {
29 | max-width: 730px;
30 | margin: 0 auto 0;
31 | }
32 |
33 | .centerContent h3 {
34 | margin: 0;
35 | }
36 |
37 | @media (min-width: 768px) {
38 | .container {
39 | padding-top: 0;
40 | }
41 |
42 | .centerContent svg {
43 | width: 85px;
44 | display: block;
45 | text-align: center;
46 | margin: 100px auto -30px;
47 | }
48 |
49 | .wrapper {
50 | display: grid;
51 | grid-template-columns: 250px minmax(0, 1fr);
52 | }
53 | }
54 |
55 | @media (min-width: 1024px) {
56 | .wrapper {
57 | display: grid;
58 | grid-template-columns: 300px minmax(0, 1fr);
59 | }
60 |
61 | .centerContent svg {
62 | margin: 100px auto -50px;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/origin-src/styles/table.module.css:
--------------------------------------------------------------------------------
1 | .table {
2 | border-collapse: collapse;
3 | width: 100%;
4 | }
5 |
6 | .table td {
7 | padding: 6px 15px 6px 0;
8 | line-height: 1.4;
9 | font-size: 0.875rem;
10 | }
11 |
12 | .table td > h5:first-child,
13 | .table td > p:first-child,
14 | .table td > ul:first-child,
15 | .table td > ul li:first-child > p {
16 | margin-top: 0 !important;
17 | }
18 |
19 | .table td > ul li {
20 | margin: 0.5rem 0;
21 | }
22 |
23 | .table td > ul li:first-child {
24 | margin-top: 0;
25 | }
26 |
27 | .table td > ul li:last-child {
28 | margin-bottom: 0;
29 | }
30 |
31 | .table td:last-child {
32 | padding-right: 0;
33 | }
34 |
35 | .tableWrapper {
36 | -webkit-overflow-scrolling: touch;
37 | overflow-y: hidden;
38 | overflow-x: auto;
39 | }
40 |
41 | @media (min-width: 768px) {
42 | .mobileTypeText {
43 | margin-top: 0px;
44 | display: inline;
45 | }
46 |
47 | .tableWrapper::-webkit-scrollbar {
48 | height: 8px;
49 | }
50 |
51 | .tableWrapper::-webkit-scrollbar-track {
52 | background: var(--color-button-blue);
53 | border-radius: 10px;
54 | }
55 |
56 | .tableWrapper::-webkit-scrollbar-thumb {
57 | background: var(--color-medium-blue);
58 | border-radius: 10px;
59 | }
60 |
61 | .tableWrapper::-webkit-scrollbar-thumb:hover {
62 | background: var(--color-light-pink);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/origin-src/types/global.d.ts:
--------------------------------------------------------------------------------
1 | interface Window {
2 | docsearch?: (options: {
3 | appId: string
4 | apiKey: string
5 | indexName: string
6 | inputSelector: string
7 | }) => vod
8 | }
9 |
10 | declare module "*.mdx" {
11 | export const meta: {
12 | title: string
13 | description: string
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/origin-src/types/little-state-machine.d.ts:
--------------------------------------------------------------------------------
1 | import "little-state-machine"
2 |
3 | declare module "little-state-machine" {
4 | export interface FormDataItem {
5 | name: string
6 | type: string
7 | required: boolean
8 | max: string
9 | min: string
10 | maxLength: string
11 | minLength: string
12 | pattern: string
13 | /** Available when type is `select` or `radio` */
14 | options?: string
15 | }
16 |
17 | interface GlobalState {
18 | formData: FormDataItem[]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/origin-src/types/types.ts:
--------------------------------------------------------------------------------
1 | export type Pages = {
2 | pathname: string
3 | name: string
4 | pages?: {
5 | pathname: string
6 | name: string
7 | }[]
8 | }[]
9 |
--------------------------------------------------------------------------------
/public/images/casinoreviews.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/casinoreviews.png
--------------------------------------------------------------------------------
/public/images/dev-tool.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/dev-tool.png
--------------------------------------------------------------------------------
/public/images/formik.min.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/formik.min.png
--------------------------------------------------------------------------------
/public/images/gatsby-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/gatsby-icon.png
--------------------------------------------------------------------------------
/public/images/hookForm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/hookForm.png
--------------------------------------------------------------------------------
/public/images/hookform.min.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/hookform.min.png
--------------------------------------------------------------------------------
/public/images/logo/react-hook-form-logo-grey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/logo/react-hook-form-logo-grey.png
--------------------------------------------------------------------------------
/public/images/logo/react-hook-form-logo-only-grey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/logo/react-hook-form-logo-only-grey.png
--------------------------------------------------------------------------------
/public/images/logo/react-hook-form-logo-only-grey.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/images/logo/react-hook-form-logo-only.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/logo/react-hook-form-logo-only.png
--------------------------------------------------------------------------------
/public/images/logo/react-hook-form-logo-only.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/images/logo/react-hook-form-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/logo/react-hook-form-logo.png
--------------------------------------------------------------------------------
/public/images/open-link.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/images/react-hook-form-og.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/react-hook-form-og.png
--------------------------------------------------------------------------------
/public/images/reduxform.min.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/reduxform.min.png
--------------------------------------------------------------------------------
/public/images/route4me.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/images/route4me.png
--------------------------------------------------------------------------------
/public/video/react-hook-form-demo-video.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/video/react-hook-form-demo-video.mp4
--------------------------------------------------------------------------------
/public/video/react-hook-form-native-demo-video.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamsurang/react-ko-form/c14f153ad361bed6c6e49c765594a08b18a5d087/public/video/react-hook-form-native-demo-video.mp4
--------------------------------------------------------------------------------
/src/components/Admonition.module.css:
--------------------------------------------------------------------------------
1 | .admonition {
2 | margin-top: 1rem;
3 | margin-bottom: 1em;
4 | padding: 15px 30px 15px 15px;
5 | border-radius: 0.4rem;
6 | }
7 |
8 | .admonitionIcon {
9 | display: inline-block;
10 | vertical-align: middle;
11 | margin-right: 0.2em;
12 | }
13 |
14 | .admonitionIcon svg {
15 | display: inline-block;
16 | width: 22px;
17 | height: 22px;
18 | stroke-width: 0;
19 | }
20 |
21 | .admonitionIcon svg {
22 | stroke: var(--color-black);
23 | fill: var(--color-black);
24 | }
25 |
26 | :global(.dark) .admonitionIcon svg {
27 | stroke: rgb(253, 253, 254);
28 | fill: rgb(253, 253, 254);
29 | }
30 |
31 | .admonitionContent > :last-child {
32 | margin-bottom: 0;
33 | }
34 |
35 | /** Customization */
36 | .admonitionWarning {
37 | background-color: rgba(230, 126, 34, 0.1);
38 | border-left: 8px solid var(--color-orange);
39 | }
40 |
41 | .admonitionTip {
42 | background-color: rgba(46, 204, 113, 0.1);
43 | border-left: 8px solid var(--color-green);
44 | }
45 |
46 | .admonitionCaution {
47 | background-color: rgba(231, 76, 60, 0.1);
48 | border-left: 8px solid var(--color-secondary);
49 | }
50 |
51 | .admonitionImportant {
52 | background-color: rgb(25, 60, 71, 0.1);
53 | border-left: 8px solid var(--color-blue);
54 | }
55 |
56 | .admonitionNote {
57 | background-color: rgb(71, 71, 72, 0.1);
58 | border-left: 8px solid var(--color-text);
59 | }
60 |
61 | .admonitionQuestion {
62 | background-color: rgba(8, 61, 119, 0.1);
63 | border-left: 8px solid var(--color-light-blue);
64 | }
65 |
--------------------------------------------------------------------------------
/src/components/ApiPage.module.css:
--------------------------------------------------------------------------------
1 | .mobileTypeText {
2 | font-weight: 400;
3 | font-size: 15px;
4 | font-family: monospace;
5 | font-variant-ligatures: none;
6 | color: var(--color-light-pink);
7 | margin-top: 10px;
8 | display: block;
9 | }
10 |
11 | .quickSelect {
12 | position: relative;
13 | max-width: 320px;
14 | margin: 0 auto;
15 | }
16 |
17 | .quickSelect:after {
18 | content: "▼";
19 | font-size: 15px;
20 | right: 17%;
21 | top: 12px;
22 | position: absolute;
23 | pointer-events: none;
24 | }
25 |
26 | .quickSelect > select {
27 | border-radius: 4px;
28 | border: 1px solid var(--color-light-blue);
29 | appearance: none;
30 | background: none;
31 | color: white;
32 | margin: 0.67em auto 20px;
33 | display: block;
34 | text-align: center;
35 | text-align-last: center;
36 | font-size: 2rem;
37 | font-weight: lighter;
38 | position: relative;
39 | padding: 10px 30px;
40 | max-width: 240px;
41 | }
42 |
43 | .versionToggle {
44 | position: absolute;
45 | right: 20px;
46 | }
47 |
48 | @media (min-width: 768px) {
49 | .hiddenMenu > h1 {
50 | display: block;
51 | }
52 |
53 | .hiddenMenu > div {
54 | display: none;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/components/ClipBoard.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react"
2 | import generic from "../data/generic"
3 |
4 | const ClipBoard = ({
5 | className,
6 | onClick,
7 | }: {
8 | onClick: () => void
9 | className?: string
10 | }) => {
11 | const [copiedCode, setCopiedCode] = useState(false)
12 |
13 | useEffect(() => {
14 | if (!copiedCode) {
15 | return
16 | }
17 |
18 | const timerId = setTimeout(() => {
19 | setCopiedCode(false)
20 | }, 3000)
21 |
22 | return () => {
23 | clearTimeout(timerId)
24 | }
25 | }, [copiedCode])
26 |
27 | return (
28 |
38 | )
39 | }
40 |
41 | export default ClipBoard
42 |
--------------------------------------------------------------------------------
/src/components/CodeArea.module.css:
--------------------------------------------------------------------------------
1 | .buttonWrapper {
2 | display: flex;
3 | position: absolute;
4 | top: 10px;
5 | right: 5px;
6 | }
7 |
8 | .button {
9 | border: none;
10 | color: white;
11 | border-radius: 0;
12 | font-size: 13px;
13 | padding: 0 10px;
14 | right: 20px;
15 | z-index: 1;
16 | top: 10px;
17 | display: none;
18 | cursor: pointer;
19 | text-transform: uppercase;
20 | height: 34px;
21 | align-items: center;
22 | margin: 0 3px;
23 | }
24 |
25 | .codeLink {
26 | background: var(--color-light-blue);
27 | border: 1px solid transparent;
28 | }
29 |
30 | .button:hover {
31 | background: var(--color-secondary);
32 | color: white;
33 | }
34 |
35 | @media (min-width: 768px) {
36 | .button {
37 | display: flex;
38 | }
39 | }
40 |
41 | .copyButton {
42 | background: none;
43 | border: 1px solid transparent;
44 | color: currentColor;
45 | }
46 |
47 | .active,
48 | .copyButton:hover {
49 | background: none;
50 | border: 1px solid var(--color-secondary);
51 | color: white;
52 | }
53 |
54 | .active,
55 | .copyButton:hover span {
56 | background: var(--color-primary);
57 | }
58 |
59 | .linkToSandBox {
60 | text-decoration: none;
61 | line-height: 2;
62 | right: 115px;
63 | color: inherit;
64 | }
65 |
66 | .linkToSandBox > svg {
67 | display: inline-block;
68 | height: 18px;
69 | position: relative;
70 | margin-right: 8px;
71 | }
72 |
--------------------------------------------------------------------------------
/src/components/CodeCompareSection.module.css:
--------------------------------------------------------------------------------
1 | .gridView {
2 | display: flex;
3 | flex-direction: column;
4 | }
5 |
6 | .gridView > div:first-child {
7 | order: 1;
8 | }
9 |
10 | .gridView iframe {
11 | display: none;
12 | box-shadow: 0 0 20px #010817;
13 | }
14 |
15 | .fullScreen {
16 | background: none;
17 | color: white;
18 | position: absolute;
19 | z-index: 1;
20 | right: 0;
21 | font-size: 12px;
22 | border-top: none;
23 | border-right: none;
24 | border-color: var(--color-secondary);
25 | border-bottom-left-radius: 4px;
26 | display: none;
27 | }
28 |
29 | .fullScreen:hover {
30 | background: var(--color-light-pink);
31 | }
32 |
33 | @media (min-width: 1000px) {
34 | .gridView {
35 | display: grid;
36 | grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
37 | grid-column-gap: 40px;
38 | max-width: 1024px;
39 | margin: 0 auto;
40 | }
41 |
42 | .gridView iframe {
43 | display: block;
44 | }
45 |
46 | .gridView > div:first-child {
47 | order: 0;
48 | }
49 |
50 | .fullScreen {
51 | display: block;
52 | }
53 |
54 | .display {
55 | display: none;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/components/CodeSandbox.tsx:
--------------------------------------------------------------------------------
1 | import styles from "./CodeArea.module.css"
2 |
3 | export const CodeSandBoxLink = ({
4 | url,
5 | isJS,
6 | isExpo,
7 | }: {
8 | url?: string
9 | isExpo?: boolean
10 | isJS?: boolean
11 | }) => (
12 |
18 | {!isExpo && (
19 |
27 | )}{" "}
28 | {isExpo ? "Expo" : "CodeSandbox"}{" "}
29 | {typeof isJS === "boolean" && (
30 |
36 | {isJS ? "JS" : "TS"}
37 |
38 | )}
39 |
40 | )
41 |
--------------------------------------------------------------------------------
/src/components/DevToolFeaturesList.module.css:
--------------------------------------------------------------------------------
1 | .featuresContent {
2 | text-align: center;
3 | }
4 |
5 | .featuresContent h3 {
6 | font-weight: 400;
7 | font-size: 20px;
8 | margin-top: 10px;
9 | }
10 |
11 | .featuresContent svg {
12 | fill: var(--color-text);
13 | width: 50px;
14 | display: block;
15 | margin: 0 auto;
16 | height: 60px;
17 | }
18 |
19 | .featuresContent > article {
20 | padding-bottom: 30px;
21 | }
22 |
23 | .featuresContent > article > div {
24 | transform: scale(0);
25 | }
26 |
27 | .features {
28 | margin-top: -60px;
29 | }
30 |
31 | .features > h2 {
32 | margin-bottom: 30px;
33 | }
34 |
35 | @media (min-width: 768px) {
36 | .featuresContent h3 {
37 | font-size: 22px;
38 | }
39 |
40 | .features > h2 {
41 | max-width: 450px;
42 | margin: 0 auto 20px;
43 | }
44 |
45 | .features {
46 | margin-top: 60px;
47 | }
48 |
49 | .featuresContent {
50 | display: grid;
51 | grid-template-columns: repeat(3, 1fr);
52 | grid-column-gap: 40px;
53 | max-width: 800px;
54 | margin: 20px auto 30px;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/components/DevTools.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | display: grid;
3 | }
4 |
5 | .devToolImg {
6 | height: 230px;
7 | margin: 30px auto 80px;
8 | display: block;
9 | cursor: not-allowed;
10 | border-radius: 5px;
11 | }
12 |
13 | .devTool ::-webkit-scrollbar {
14 | }
15 |
16 | .devTool ::-webkit-scrollbar-track {
17 | background: inherit;
18 | }
19 |
20 | .devTool ::-webkit-scrollbar-thumb {
21 | background: grey;
22 | }
23 |
24 | .devTool ::-webkit-scrollbar-thumb:hover {
25 | background: black;
26 | }
27 |
28 | .demo {
29 | display: grid;
30 | grid-gap: 30px;
31 | max-width: 768px;
32 | margin: 0 auto;
33 | }
34 |
35 | .demo > div:first-child {
36 | order: 2;
37 | }
38 |
39 | @media (min-width: 768px) {
40 | .devToolImg {
41 | max-width: 600px;
42 | margin: 50px auto 0;
43 | display: block;
44 | height: auto;
45 | border-radius: 8px;
46 | min-height: 420px;
47 | }
48 |
49 | .demo {
50 | display: grid;
51 | grid-gap: 30px;
52 | grid-template-columns: 1fr 1fr;
53 | max-width: 768px;
54 | margin: 0 auto;
55 | }
56 |
57 | .demo > div:first-child {
58 | order: 0;
59 | }
60 | }
61 |
62 | @media (min-width: 1024px) {
63 | .devTool {
64 | display: block;
65 | }
66 |
67 | .devToolImg {
68 | max-width: 800px;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/components/FeatureList.module.css:
--------------------------------------------------------------------------------
1 | .featuresContent {
2 | text-align: center;
3 | }
4 |
5 | .featuresContent h3 {
6 | font-weight: 500;
7 | font-size: 20px;
8 | margin-top: 10px;
9 | }
10 |
11 | .featuresContent svg {
12 | width: 50px;
13 | display: block;
14 | margin: 0 auto;
15 | height: 60px;
16 | }
17 |
18 | .featuresContent > article {
19 | padding-bottom: 30px;
20 | }
21 |
22 | .featuresContent > article > div {
23 | transform: scale(0);
24 | }
25 |
26 | .features {
27 | margin-top: -60px;
28 | }
29 |
30 | .features > h2 {
31 | margin-bottom: 30px;
32 | }
33 |
34 | @media (min-width: 768px) {
35 | .featuresContent h3 {
36 | font-size: 22px;
37 | }
38 |
39 | .features > h2 {
40 | max-width: 450px;
41 | margin: 0 auto 20px;
42 | }
43 |
44 | .features {
45 | margin-top: 60px;
46 | margin-bottom: 60px;
47 | }
48 |
49 | .featuresContent {
50 | display: grid;
51 | grid-template-columns: repeat(3, 1fr);
52 | grid-column-gap: 30px;
53 | max-width: 1024px;
54 | margin: 40px auto 30px;
55 | }
56 | }
57 |
58 | @media (min-width: 1280px) {
59 | .featuresContent {
60 | grid-template-columns: repeat(6, 1fr);
61 | grid-column-gap: 25px;
62 | max-width: 1480px;
63 | }
64 |
65 | .featuresContent > article {
66 | padding-bottom: 0;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/components/Footer.module.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | padding: 40px 0;
3 | font-size: 0.8rem;
4 | font-weight: 400;
5 | text-align: center;
6 | }
7 |
8 | .footer a {
9 | color: var(--color-footer);
10 | text-decoration: none;
11 | }
12 |
13 | .footer a:hover {
14 | color: var(--color-light-pink);
15 | text-decoration: none;
16 | }
17 |
18 | .footer > p {
19 | font-size: 13px;
20 | }
21 |
22 | .links {
23 | border-bottom: 1px solid var(--color-light-pink);
24 | max-width: 900px;
25 | margin: 0 auto 20px;
26 | padding: 0 0 10px 0;
27 | display: block;
28 | }
29 |
30 | .links > li {
31 | display: inline-flex;
32 | }
33 |
34 | .links > li > a {
35 | text-decoration: none;
36 | color: var(--color-text);
37 | padding: 10px 12px;
38 | min-width: 48px;
39 | min-height: 48px;
40 | }
41 |
42 | a.link {
43 | color: var(--color-primary);
44 | }
45 |
46 | .logoGroup {
47 | display: flex;
48 | justify-content: center;
49 | align-items: center;
50 | gap: 1rem;
51 | }
52 |
53 | .logoGroup img {
54 | width: 100px;
55 | }
56 |
57 | .heading {
58 | font-size: 0.6rem;
59 | font-weight: 600;
60 | margin-bottom: -0.2rem;
61 | }
62 |
--------------------------------------------------------------------------------
/src/components/Form.module.css:
--------------------------------------------------------------------------------
1 | .code {
2 | padding: 0 20px;
3 | white-space: pre-wrap;
4 | font-size: 0.7rem;
5 | line-height: 1.6;
6 | }
7 |
8 | .wrapper {
9 | display: grid;
10 | min-height: 700px;
11 | transition: 1s all;
12 | grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
13 | grid-column-gap: 40px;
14 | max-width: 1440px;
15 | margin: 20px auto 0;
16 | }
17 |
18 | .demoForm {
19 | flex: 1;
20 | }
21 |
22 | .demoForm > select,
23 | .demoForm > input,
24 | .input {
25 | display: block;
26 | box-sizing: border-box;
27 | width: 100%;
28 | border-radius: 4px;
29 | padding: 6px 10px;
30 | margin-bottom: 10px;
31 | font-size: 0.9rem;
32 | }
33 |
34 | .demoForm > select:not([multiple]) {
35 | height: 43px;
36 | }
37 |
--------------------------------------------------------------------------------
/src/components/FormFields.module.css:
--------------------------------------------------------------------------------
1 | .radioGroup {
2 | display: flex;
3 | margin-bottom: 20px;
4 | }
5 |
6 | .radioGroup > label:not(:last-child) {
7 | margin-right: 20px;
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/FormStateTable.tsx:
--------------------------------------------------------------------------------
1 | import generic from "../data/generic"
2 | import API from "../data/api"
3 | import typographyStyles from "../styles/typography.module.css"
4 | import tableStyles from "../styles/table.module.css"
5 | import { FormStateApi } from "./FormStateApi"
6 |
7 | export default function FormStateTable({ api }: { api: typeof API }) {
8 | return (
9 | <>
10 |
11 | Return
12 |
13 |
14 |
15 |
16 |
17 | {generic.name} |
18 | {generic.type} |
19 | {generic.description} |
20 |
21 |
22 |
23 |
24 |
25 | >
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/GetStarted.module.css:
--------------------------------------------------------------------------------
1 | .copyButton {
2 | display: none;
3 | background: var(--color-light-blue);
4 | color: white;
5 | font-size: 13px;
6 | float: right;
7 | text-transform: uppercase;
8 | border: 1px solid transparent;
9 | margin-top: -2px;
10 | cursor: pointer;
11 | }
12 |
13 | .copyButton:hover {
14 | background: none;
15 | border: 1px solid var(--color-secondary);
16 | color: white;
17 | }
18 |
19 | .copyButton:hover span {
20 | background: var(--color-primary);
21 | }
22 |
23 | @media (min-width: 768px) {
24 | .copyButton {
25 | display: inline-block;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/HomePage.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | padding: 0 20px 50px;
3 | position: relative;
4 | }
5 |
6 | .feedback {
7 | margin-top: 40px;
8 | }
9 |
10 | .feedback > div {
11 | border-radius: 15px;
12 | margin-bottom: 20px;
13 | }
14 |
15 | .feedback svg {
16 | margin: 0 auto 10px;
17 | width: 45px;
18 | }
19 |
20 | .feedback > div > p {
21 | font-size: 15px;
22 | text-align: left;
23 | padding: 20px 0;
24 | }
25 |
26 | @media (min-width: 768px) {
27 | .feedback {
28 | display: grid;
29 | grid-template-columns: repeat(3, 1fr);
30 | grid-gap: 50px;
31 | }
32 |
33 | .feedback > div {
34 | margin-bottom: 0;
35 | }
36 | }
37 |
38 | @media (min-width: 1024px) {
39 | .root {
40 | padding: 0 50px;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/IsolateRender.module.css:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | display: grid;
3 | grid-gap: 20px;
4 | margin-top: 20px;
5 | grid-template-columns: 1fr 1fr;
6 | position: relative;
7 | }
8 |
9 | .wrapper > div {
10 | display: none;
11 | }
12 |
13 | .wrapper p {
14 | font-size: 45px;
15 | font-weight: 800;
16 | margin-top: 160px;
17 | line-height: 1.4;
18 | }
19 |
20 | .wrapper h2 {
21 | font-size: 14px;
22 | }
23 |
24 | .externalComponent {
25 | font-size: 14px;
26 | border: 1px solid var(--color-secondary);
27 | padding: 10px 0;
28 | border-radius: 4px;
29 | margin: 20px 0;
30 | }
31 |
32 | .line {
33 | position: absolute;
34 | width: 1px;
35 | background: var(--color-blue);
36 | height: 44%;
37 | left: 50%;
38 | top: 30%;
39 | z-index: -1;
40 | }
41 |
42 | @media (min-width: 768px) {
43 | .wrapper {
44 | grid-gap: 40px;
45 | grid-template-columns: 1fr 65px 1fr;
46 | }
47 |
48 | .wrapper > div {
49 | display: block;
50 | }
51 |
52 | .wrapper h2 {
53 | font-size: 24px;
54 | font-weight: 400;
55 | padding-bottom: 10px;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/components/Menu/index.ts:
--------------------------------------------------------------------------------
1 | import Menu from "./Menu"
2 | import {
3 | apiLinks,
4 | faqLinks,
5 | advancedLinks,
6 | tsLinks,
7 | getStartedLinks,
8 | } from "./MenuLinks"
9 |
10 | const links = {
11 | apiLinks,
12 | faqLinks,
13 | advancedLinks,
14 | tsLinks,
15 | getStartedLinks,
16 | }
17 |
18 | export {
19 | Menu,
20 | apiLinks,
21 | faqLinks,
22 | advancedLinks,
23 | tsLinks,
24 | getStartedLinks,
25 | links,
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/Popup.module.css:
--------------------------------------------------------------------------------
1 | .iconStyle,
2 | .icon,
3 | .button {
4 | border-radius: 50%;
5 | border: none;
6 | height: 18px;
7 | width: 18px;
8 | font-size: 15px;
9 | display: inline-flex;
10 | margin-left: 10px;
11 | justify-content: center;
12 | align-items: center;
13 | line-height: 1;
14 | }
15 |
16 | .icon {
17 | border: 1px solid var(--color-text);
18 | margin-left: 0;
19 | margin-right: 5px;
20 | }
21 |
22 | .root {
23 | font-weight: bold;
24 | position: relative;
25 | }
26 |
27 | .root > span {
28 | font-size: 14px !important;
29 | margin-left: 10px;
30 | font-weight: 400;
31 | display: inline-block;
32 | overflow: hidden;
33 | position: relative;
34 | top: 5px;
35 | }
36 |
37 | .root > span > span {
38 | display: inline-block;
39 | position: relative;
40 | font-family: sans-serif;
41 | }
42 |
43 | .button {
44 | cursor: pointer;
45 | }
46 |
47 | .button:hover {
48 | background: var(--color-light-pink);
49 | color: white;
50 | }
51 |
--------------------------------------------------------------------------------
/src/components/Popup.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react"
2 | import { Animate } from "react-simple-animate"
3 | import styles from "./Popup.module.css"
4 |
5 | function Popup({
6 | message,
7 | top,
8 | iconOnly,
9 | }: {
10 | iconOnly?: boolean
11 | message?: string
12 | top?: number
13 | }) {
14 | const [tipShow, setTipShow] = useState(false)
15 |
16 | if (iconOnly) {
17 | return !
18 | }
19 |
20 | return (
21 |
22 |
30 |
31 | (
40 |
41 | {message || <>React Native: compatible with Controller>}
42 |
43 | )}
44 | />
45 |
46 |
47 | )
48 | }
49 |
50 | export default Popup
51 |
--------------------------------------------------------------------------------
/src/components/ResourcePageArticles.tsx:
--------------------------------------------------------------------------------
1 | import containerStyle from "../styles/container.module.css"
2 | import styles from "./ResourcePage.module.css"
3 | import Footer from "./Footer"
4 | import generic from "../data/generic"
5 | import ResourceList from "./ResourceList"
6 | import resources from "../data/resources"
7 | import StarRepo from "./StarRepo"
8 |
9 | export default function ResourcePageCondensed() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/ResourcePageBindings.tsx:
--------------------------------------------------------------------------------
1 | import containerStyle from "../styles/container.module.css"
2 | import styles from "./ResourcePage.module.css"
3 | import Footer from "./Footer"
4 | import generic from "../data/generic"
5 | import ResourceList from "./ResourceList"
6 | import resources from "../data/resources"
7 | import StarRepo from "./StarRepo"
8 |
9 | export default function ResourcePageBinding() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/ResourcePageNewsletter.tsx:
--------------------------------------------------------------------------------
1 | import containerStyle from "../styles/container.module.css"
2 | import styles from "./ResourcePage.module.css"
3 | import Footer from "./Footer"
4 | import generic from "../data/generic"
5 | import ResourceList from "./ResourceList"
6 | import resources from "../data/resources"
7 | import StarRepo from "./StarRepo"
8 |
9 | export default function ResourcePageNewsletter() {
10 | return (
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/ResourcePageVideos.tsx:
--------------------------------------------------------------------------------
1 | import containerStyle from "../styles/container.module.css"
2 | import styles from "./ResourcePage.module.css"
3 | import Footer from "./Footer"
4 | import generic from "../data/generic"
5 | import ResourceList from "./ResourceList"
6 | import resources from "../data/resources"
7 | import StarRepo from "./StarRepo"
8 |
9 | export default function ResourcePageVideos() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/Search.module.css:
--------------------------------------------------------------------------------
1 | .searchForm {
2 | margin-right: 12px;
3 | position: relative;
4 | }
5 |
6 | .whiteText {
7 | color: white !important;
8 | }
9 |
10 | .searchBar {
11 | padding: 0 10px;
12 | width: 26px;
13 | border-radius: 25px;
14 | font-size: 16px;
15 | line-height: 24px;
16 | height: 26px;
17 | z-index: 1;
18 | cursor: pointer;
19 | color: var(--color-primary) !important;
20 | }
21 |
22 | .searchBarOpen {
23 | padding: 3px 14px;
24 | width: 150px;
25 | }
26 |
27 | .searchBarOpen:focus {
28 | outline: none;
29 | border: 1px solid var(--color-light-pink);
30 | cursor: default;
31 | }
32 |
33 | .icon {
34 | color: black !important;
35 | position: absolute;
36 | left: 7px;
37 | z-index: 22;
38 | top: 5px;
39 | pointer-events: none;
40 | }
41 |
42 | @media (min-width: 1600px) {
43 | .searchBar {
44 | width: 150px;
45 | padding: 3px 14px;
46 | }
47 |
48 | .icon {
49 | display: none;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/components/Search.tsx:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from "react"
2 | import clsx from "clsx"
3 | import searchStyles from "./Search.module.css"
4 | import useWindowSize from "./utils/useWindowSize"
5 | import { LARGE_SCREEN } from "../styles/breakpoints"
6 |
7 | const Search = ({
8 | focus,
9 | setFocus,
10 | }: {
11 | focus: boolean
12 | setFocus: (value: boolean) => void
13 | }) => {
14 | const { width } = useWindowSize()
15 | const searchRef = useRef(null)
16 |
17 | useEffect(() => {
18 | window.docsearch?.({
19 | appId: "Z2CKVVT2QA",
20 | apiKey: "c56a3f265ffbf85c2c654f865cb09164",
21 | indexName: "react-hook-form",
22 | inputSelector: "#algolia-doc-search",
23 | })
24 |
25 | return () => {
26 | setFocus(false)
27 | }
28 | }, [setFocus])
29 |
30 | useEffect(() => {
31 | if (LARGE_SCREEN <= width) {
32 | setFocus(true)
33 | } else {
34 | setFocus(false)
35 | searchRef.current?.blur()
36 | }
37 | }, [setFocus, width])
38 |
39 | return (
40 | <>
41 |
63 |
64 | >
65 | )
66 | }
67 |
68 | export default Search
69 |
--------------------------------------------------------------------------------
/src/components/SortableContainer.module.css:
--------------------------------------------------------------------------------
1 | .list {
2 | border: 1px solid var(--color-light-blue);
3 | padding: 14px 14px 14px 50px;
4 | border-radius: 4px;
5 | margin-bottom: 10px;
6 | background: var(--color-primary);
7 | cursor: move;
8 | position: relative;
9 | list-style: none;
10 | color: white;
11 | }
12 |
13 | .list > svg {
14 | fill: white;
15 | display: inline-block;
16 | width: 20px;
17 | position: absolute;
18 | left: 15px;
19 | top: 17px;
20 | }
21 |
22 | .editPanel {
23 | float: right;
24 | }
25 |
26 | .editPanel > button {
27 | position: relative;
28 | color: white;
29 | top: -2px;
30 | font-size: 14px;
31 | cursor: pointer;
32 | padding: 1px 8px;
33 | background: var(--color-light-blue);
34 | border: 1px solid transparent;
35 | text-transform: uppercase;
36 | letter-spacing: 1px;
37 | }
38 |
39 | .editPanel > button:hover {
40 | background: var(--color-primary);
41 | border: 1px solid var(--color-secondary);
42 | }
43 |
44 | .editPanel > button:first-child {
45 | margin-right: 14px;
46 | }
47 |
48 | .sortableWrapper {
49 | margin-top: 30px;
50 | }
51 |
52 | .sortableWrapper > ul {
53 | margin-left: 0;
54 | padding-left: 0;
55 | }
56 |
--------------------------------------------------------------------------------
/src/components/StarRepo.tsx:
--------------------------------------------------------------------------------
1 | import generic from "../data/generic"
2 | import buttonStyles from "../styles/button.module.css"
3 | import containerStyles from "../styles/container.module.css"
4 |
5 | export default function StarRepo() {
6 | return (
7 |
11 |
{generic.needYourSupport.title}
12 |
{generic.needYourSupport.description}
13 |
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/TabGroup.module.css:
--------------------------------------------------------------------------------
1 | .buttonTabGroup {
2 | display: grid;
3 | grid-auto-flow: column;
4 | }
5 |
6 | .buttonTabGroup > button {
7 | color: var(--color-text);
8 | background: var(--color-background);
9 | padding: 5px 8px 5px;
10 | font-size: 12px;
11 | border: none;
12 | transition: 0.3s all;
13 | text-transform: uppercase;
14 | }
15 |
16 | .buttonTabGroup > button:nth-child(n + 2) {
17 | margin-left: 3px;
18 | }
19 |
20 | .buttonTabGroup > button:hover {
21 | background: var(--color-secondary);
22 | }
23 |
24 | .buttonTabGroup > button:disabled {
25 | border-top: 1px solid var(--color-secondary);
26 | background: var(--color-primary);
27 | color: white;
28 | cursor: not-allowed;
29 | }
30 |
31 | @media (min-width: 768px) {
32 | .buttonTabGroup > button {
33 | padding: 5px 20px 5px;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/TabGroup.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react"
2 | import type { ReactNode } from "react"
3 | import styles from "./TabGroup.module.css"
4 |
5 | const TabGroup = ({
6 | children,
7 | buttonLabels,
8 | }: {
9 | children: ReactNode[]
10 | buttonLabels: string[]
11 | }) => {
12 | const [index, setIndex] = useState(0)
13 |
14 | return (
15 |
16 |
20 | {buttonLabels.map((label, currentIndex) => (
21 |
33 | ))}
34 |
35 | {children.map((child, currentIndex) => {
36 | return (
37 |
43 | {child}
44 |
45 | )
46 | })}
47 |
48 | )
49 | }
50 |
51 | export default TabGroup
52 |
--------------------------------------------------------------------------------
/src/components/Toggle.module.css:
--------------------------------------------------------------------------------
1 | /* The toggle - the box around the slider */
2 | .toggle {
3 | position: relative;
4 | display: inline-block;
5 | width: 40px;
6 | height: 26px;
7 | z-index: 1;
8 | margin-right: 12px;
9 | }
10 |
11 | /* Hide default HTML checkbox */
12 | .toggle input {
13 | opacity: 0;
14 | width: 0;
15 | height: 0;
16 | }
17 |
18 | /* The slider */
19 | .slider {
20 | position: absolute;
21 | cursor: pointer;
22 | top: 0;
23 | left: 0;
24 | right: 0;
25 | bottom: 0;
26 | background-color: white;
27 | -webkit-transition: 0.2s;
28 | transition: 0.2s;
29 | border: 1px solid transparent;
30 | }
31 |
32 | .slider:before {
33 | position: absolute;
34 | content: "";
35 | top: 1px;
36 | height: 22px;
37 | width: 20px;
38 | left: 2px;
39 | bottom: 4px;
40 | background-color: var(--color-blue);
41 | -webkit-transition: 0.2s;
42 | transition: 0.2s;
43 | }
44 |
45 | input:checked + .slider {
46 | background-color: var(--color-light-blue);
47 | }
48 |
49 | input:checked + .slider:before {
50 | background: white;
51 | }
52 |
53 | input:focus + .slider {
54 | border: 1px solid var(--color-light-pink);
55 | }
56 |
57 | input:checked + .slider:before {
58 | -webkit-transform: translateX(14px);
59 | -ms-transform: translateX(14px);
60 | transform: translateX(14px);
61 | }
62 |
63 | /* Rounded sliders */
64 | .slider.round {
65 | border-radius: 30px;
66 | }
67 |
68 | .slider.round:before {
69 | border-radius: 50%;
70 | }
71 |
--------------------------------------------------------------------------------
/src/components/Toggle.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties, useEffect, useState } from "react"
2 | import styles from "./Toggle.module.css"
3 | import { useTheme } from "next-themes"
4 |
5 | export default function Toggle({ style }: { style?: CSSProperties }) {
6 | const [mounted, setMounted] = useState(false)
7 |
8 | const { theme, setTheme } = useTheme()
9 | const lightMode = theme === "light"
10 |
11 | // useEffect only runs on the client, so now we can safely show the UI
12 | useEffect(() => {
13 | setMounted(true)
14 | }, [])
15 |
16 | if (!mounted) {
17 | return null
18 | }
19 |
20 | return (
21 | // eslint-disable-next-line jsx-a11y/label-has-associated-control
22 |
37 | )
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/TypeText.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from "react"
2 | import typographyStyles from "../styles/typography.module.css"
3 |
4 | const TypeText = ({
5 | children,
6 | pre = false,
7 | }: {
8 | children: ReactNode
9 | pre: boolean
10 | }) => {
11 | const Element = pre ? "pre" : "span"
12 | return {children}
13 | }
14 |
15 | export default TypeText
16 |
--------------------------------------------------------------------------------
/src/components/UseController.tsx:
--------------------------------------------------------------------------------
1 | import api from "../data/api"
2 | import typographyStyles from "../styles/typography.module.css"
3 | import Footer from "./Footer"
4 | import containerStyles from "../styles/container.module.css"
5 | import UseControllerContent from "./UseControllerContent"
6 | import StarRepo from "./StarRepo"
7 | import { Menu, apiLinks } from "./Menu"
8 |
9 | export default function UseController() {
10 | return (
11 |
12 |
13 | useController
14 |
15 |
16 | 제어 컴포넌트를 위한 리액트 훅
17 |
18 |
19 |
20 |
21 |
22 |
23 |
28 |
29 |
30 |
31 |
32 |
33 | )
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/UseFieldArray.tsx:
--------------------------------------------------------------------------------
1 | import api from "../data/api"
2 | import typographyStyles from "../styles/typography.module.css"
3 | import Footer from "./Footer"
4 | import containerStyles from "../styles/container.module.css"
5 | import UseFieldArrayContent from "./UseFieldArrayContent"
6 | import StarRepo from "./StarRepo"
7 | import { Menu, apiLinks } from "./Menu"
8 |
9 | export default function UseFieldArray() {
10 | return (
11 |
12 |
13 | useFieldArray
14 |
15 |
필드 배열을 위한 React 훅
16 |
17 |
18 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
30 |
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/Watcher.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | display: none;
3 | }
4 |
5 | .svgWrapper {
6 | width: 200px;
7 | }
8 |
9 | .watchGroup {
10 | display: flex;
11 | height: 50px;
12 | }
13 |
14 | .watchGroup p {
15 | margin-top: 5px;
16 | padding: 0 0 0 50px;
17 | }
18 |
19 | .watchGroup input[type="checkbox"] {
20 | width: 20px;
21 | margin-top: 8px;
22 | margin-left: -60px;
23 | height: 20px;
24 | background: var(--color-background);
25 | border: 1px solid var(--color-secondary);
26 | border-radius: 2px;
27 | }
28 |
29 | .watchGroup input[type="checkbox"]:checked {
30 | border: 1px solid white;
31 | background: var(--color-primary);
32 | min-width: 20px;
33 | }
34 |
35 | .svgWrapper svg {
36 | width: 100%;
37 | }
38 |
39 | .svgWrapper svg path {
40 | stroke-dasharray: 10;
41 | animation: dash 10s linear normal infinite;
42 | }
43 |
44 | .behind {
45 | background: var(--color-background);
46 | }
47 |
48 | .closed {
49 | color: var(--color-background);
50 | }
51 |
52 | @keyframes dash {
53 | from {
54 | stroke-dashoffset: 500;
55 | }
56 | to {
57 | stroke-dashoffset: 0;
58 | }
59 | }
60 |
61 | @media (min-width: 768px) {
62 | .watcher {
63 | display: block;
64 | }
65 |
66 | .root {
67 | display: grid;
68 | margin: 40px auto;
69 | max-width: 800px;
70 | grid-template-columns: 1fr 1fr 200px;
71 | }
72 |
73 | .svgWrapper {
74 | display: block;
75 | width: 300px;
76 | }
77 |
78 | .svgWrapper svg {
79 | height: 200px;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/components/codeExamples/dependantFieldsTS.tsx:
--------------------------------------------------------------------------------
1 | export default `import * as React from "react";
2 | import { useForm } from "react-hook-form";
3 |
4 | type FormValues = {
5 | a: string;
6 | b: string;
7 | c: string;
8 | };
9 |
10 | export default function App() {
11 | const { watch, register, handleSubmit, setValue, formState } = useForm<
12 | FormValues
13 | >({
14 | defaultValues: {
15 | a: "",
16 | b: "",
17 | c: ""
18 | }
19 | });
20 | const onSubmit = (data: FormValues) => console.log(data);
21 | const [a, b] = watch(["a", "b"]);
22 |
23 | React.useEffect(() => {
24 | if (formState.touchedFields.a && formState.touchedFields.b && a && b) {
25 | setValue("c", \`\${a} \${b}\`);
26 | }
27 | }, [setValue, a, b, formState]);
28 |
29 | return (
30 |
46 | );
47 | }
48 | `
49 |
--------------------------------------------------------------------------------
/src/components/codeExamples/devTool.tsx:
--------------------------------------------------------------------------------
1 | export default `import { useForm } from "react-hook-form";
2 | import { DevTool } from "@hookform/devtools";
3 |
4 | export default () => {
5 | const { register, control, handleSubmit } = useForm({
6 | mode: "onChange",
7 | });
8 |
9 | return (
10 | <>
11 |
19 |
20 | {/* set up the dev tool */}
21 | >
22 | );
23 | };
24 | `
25 |
--------------------------------------------------------------------------------
/src/components/codeExamples/formState.ts:
--------------------------------------------------------------------------------
1 | export default `import React from "react";
2 | import { useForm } from "react-hook-form";
3 |
4 | export default function App() {
5 | const {
6 | register,
7 | handleSubmit,
8 | // 렌더링 전에 formState를 읽어 Proxy를 통해 폼 상태를 구독하세요.
9 | formState: { errors, isDirty, isSubmitting, touchedFields, submitCount },
10 | } = useForm();
11 | const onSubmit = (data) => console.log(data);
12 |
13 | return (
14 |
18 | );
19 | }
20 | `
21 |
--------------------------------------------------------------------------------
/src/components/codeExamples/formStateTs.ts:
--------------------------------------------------------------------------------
1 | export default `import { useForm } from "react-hook-form";
2 |
3 | type FormInputs = {
4 | test: string
5 | }
6 |
7 | export default function App() {
8 | const {
9 | register,
10 | handleSubmit,
11 | // Read the formState before render to subscribe the form state through Proxy
12 | formState: { errors, isDirty, isSubmitting, touchedFields, submitCount },
13 | } = useForm();
14 | const onSubmit = (data: FormInputs) => console.log(data);
15 |
16 | return (
17 |
21 | );
22 | }
23 | `
24 |
--------------------------------------------------------------------------------
/src/components/codeExamples/formStateUseEffect.ts:
--------------------------------------------------------------------------------
1 | export default `import { useForm } from "react-hook-form";
2 |
3 | export default function App () {
4 | const {
5 | register,
6 | handleSubmit,
7 | formState
8 | } = useForm();
9 |
10 | const onSubmit = (data) => console.log(data);
11 |
12 | React.useEffect(() => {
13 | console.log("touchedFields", formState.touchedFields);
14 | },[formState]); // use entire formState object as optional array arg in useEffect, not individual properties of it
15 |
16 |
17 | return (
18 |
22 | );
23 | };
24 |
25 | `
26 |
--------------------------------------------------------------------------------
/src/components/codeExamples/formStateUseEffectTs.ts:
--------------------------------------------------------------------------------
1 | export default `import React from "react";
2 | import { useForm } from "react-hook-form";
3 | type FormInputs = {
4 | test: string
5 | }
6 | export default function App() {
7 | const {
8 | register,
9 | handleSubmit,
10 | formState
11 | } = useForm();
12 | const onSubmit = (data: FormInputs) => console.log(data);
13 |
14 | React.useEffect(() => {
15 | console.log("touchedFields", formState.touchedFields);
16 | }, [formState]);
17 |
18 | return (
19 |
23 | );
24 | }
25 | `
26 |
--------------------------------------------------------------------------------
/src/components/codeExamples/reactHookFormCode.ts:
--------------------------------------------------------------------------------
1 | export default `import { useForm } from "react-hook-form";
2 |
3 | const Example = () => {
4 | const { handleSubmit, register, formState: { errors } } = useForm();
5 | const onSubmit = values => console.log(values);
6 |
7 | return (
8 |
30 | );
31 | };
32 | `
33 |
--------------------------------------------------------------------------------
/src/components/codeExamples/useController.ts:
--------------------------------------------------------------------------------
1 | export default `import { TextField } from "@material-ui/core";
2 | import { useController, useForm } from "react-hook-form";
3 |
4 | function Input({ control, name }) {
5 | const {
6 | field,
7 | fieldState: { invalid, isTouched, isDirty },
8 | formState: { touchedFields, dirtyFields }
9 | } = useController({
10 | name,
11 | control,
12 | rules: { required: true },
13 | });
14 |
15 | return (
16 |
23 | );
24 | }
25 | `
26 |
--------------------------------------------------------------------------------
/src/components/codeExamples/useControllerTs.ts:
--------------------------------------------------------------------------------
1 | export default `import * as React from "react";
2 | import { useForm, useController, UseControllerProps } from "react-hook-form";
3 |
4 | type FormValues = {
5 | FirstName: string;
6 | };
7 |
8 | function Input(props: UseControllerProps) {
9 | const { field, fieldState } = useController(props);
10 |
11 | return (
12 |
13 |
14 |
{fieldState.isTouched && "Touched"}
15 |
{fieldState.isDirty && "Dirty"}
16 |
{fieldState.invalid ? "invalid" : "valid"}
17 |
18 | );
19 | }
20 |
21 | export default function App() {
22 | const { handleSubmit, control } = useForm({
23 | defaultValues: {
24 | FirstName: ""
25 | },
26 | mode: "onChange"
27 | });
28 | const onSubmit = (data: FormValues) => console.log(data);
29 |
30 | return (
31 |
35 | );
36 | }
37 | `
38 |
--------------------------------------------------------------------------------
/src/components/codeExamples/useFieldArray.ts:
--------------------------------------------------------------------------------
1 | export default `import React from "react";
2 | import { useForm, useFieldArray } from "react-hook-form";
3 |
4 | function App() {
5 | const { register, control, handleSubmit, reset, trigger, setError } = useForm({
6 | // defaultValues: {}; 이 속성을 사용하여 필드에 값을 채울 수 있습니다.
7 | });
8 | const { fields, append, remove } = useFieldArray({
9 | control,
10 | name: "test"
11 | });
12 |
13 | return (
14 |
36 | );
37 | }
38 | `
39 |
--------------------------------------------------------------------------------
/src/components/codeExamples/useFieldArrayArgument.ts:
--------------------------------------------------------------------------------
1 | export default `function FieldArray() {
2 | const { control, register } = useForm();
3 | const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({
4 | control, // control props는 useForm에서 제공됨 (FormProvider를 사용 중이라면 선택 사항)
5 | name: "test", // 필드 배열의 고유한 이름
6 | });
7 |
8 | return (
9 | {fields.map((field, index) => (
10 |
14 | ))}
15 | );
16 | }
17 |
18 | `
19 |
--------------------------------------------------------------------------------
/src/components/codeExamples/useFieldArrayConditional.ts:
--------------------------------------------------------------------------------
1 | export default `import React from 'react';
2 | import { useForm, useWatch, useFieldArray, Control } from 'react-hook-form';
3 |
4 | type FormValues = {
5 | data: { name: string }[];
6 | };
7 |
8 | const ConditionField = ({
9 | control,
10 | index,
11 | register,
12 | }: {
13 | control: Control;
14 | index: number;
15 | }) => {
16 | const output = useWatch({
17 | name: 'data',
18 | control,
19 | defaultValue: 'yay! I am watching you :)',
20 | });
21 |
22 | return (
23 | <>
24 | {output[index]?.name === "bill" && (
25 |
26 | )}
27 |
31 | >
32 | );
33 | };
34 |
35 | const UseFieldArrayUnregister: React.FC = () => {
36 | const { control, handleSubmit, register } = useForm({
37 | defaultValues: {
38 | data: [{ name: 'test' }, { name: 'test1' }, { name: 'test2' }],
39 | },
40 | mode: 'onSubmit',
41 | shouldUnregister: false,
42 | });
43 | const { fields } = useFieldArray({
44 | control,
45 | name: 'data',
46 | });
47 | const onSubmit = (data: FormValues) => console.log(data);
48 |
49 | return (
50 |
59 | );
60 | };
61 | `
62 |
--------------------------------------------------------------------------------
/src/components/codeExamples/useFieldArrayFocus.ts:
--------------------------------------------------------------------------------
1 | export default `import React from 'react';
2 | import { useForm, useFieldArray } from 'react-hook-form';
3 |
4 | const App = () => {
5 | const { register, control } = useForm<{
6 | test: { value: string }[];
7 | }>({
8 | defaultValues: {
9 | test: [{ value: '1' }, { value: '2' }],
10 | },
11 | });
12 | const { fields, prepend, append } = useFieldArray({
13 | name: 'test',
14 | control,
15 | });
16 |
17 | return (
18 |
35 | );
36 | };
37 | `
38 |
--------------------------------------------------------------------------------
/src/components/codeExamples/useFieldArrayPreview.ts:
--------------------------------------------------------------------------------
1 | export default `import * as React from "react";
2 | import { useForm, useFieldArray, useWatch } from "react-hook-form";
3 |
4 | export default function App() {
5 | const { control, handleSubmit } = useForm();
6 | const { fields, append, update } = useFieldArray({
7 | control,
8 | name: 'array'
9 | });
10 |
11 | return (
12 |
33 | );
34 | }
35 |
36 | const Display = ({ control, index }) => {
37 | const data = useWatch({
38 | control,
39 | name: \`array.\${index}\`
40 | });
41 | return {data?.firstName}
;
42 | };
43 |
44 | const Edit = ({ update, index, value, control }) => {
45 | const { register, handleSubmit } = useForm({
46 | defaultValues: value
47 | });
48 |
49 | return (
50 |
51 |
52 |
53 |
57 |
58 |
64 |
65 | );
66 | };
67 |
68 | `
69 |
--------------------------------------------------------------------------------
/src/components/codeExamples/useFormState.ts:
--------------------------------------------------------------------------------
1 | export default `import * as React from "react";
2 | import { useForm, useFormState } from "react-hook-form";
3 |
4 | function Child({ control }) {
5 | const { dirtyFields } = useFormState({
6 | control
7 | });
8 |
9 | return dirtyFields.firstName ? Field is dirty.
: null;
10 | };
11 |
12 | export default function App() {
13 | const { register, handleSubmit, control } = useForm({
14 | defaultValues: {
15 | firstName: "firstName"
16 | }
17 | });
18 | const onSubmit = (data) => console.log(data);
19 |
20 | return (
21 |
27 | );
28 | }
29 | `
30 |
--------------------------------------------------------------------------------
/src/components/general-observer.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FunctionComponent,
3 | RefObject,
4 | useEffect,
5 | useRef,
6 | useState,
7 | ReactNode,
8 | } from "react"
9 |
10 | interface IGeneralObserverProps {
11 | /** React Children */
12 | children: ReactNode
13 | placeholder?: ReactNode
14 | /** Fires when IntersectionObserver enters viewport */
15 | onEnter?: (id?: string) => void
16 | }
17 |
18 | export const GeneralObserver: FunctionComponent = ({
19 | children,
20 | onEnter,
21 | placeholder,
22 | }) => {
23 | const ref = useRef(null)
24 | const [isChildVisible, setIsChildVisible] = useState(false)
25 |
26 | useEffect(() => {
27 | const observer = new IntersectionObserver(
28 | ([entry]) => {
29 | if (entry.isIntersecting) {
30 | setIsChildVisible(true)
31 | onEnter?.()
32 | }
33 | },
34 | {
35 | rootMargin: "0px 0px",
36 | threshold: [1],
37 | }
38 | )
39 | if (ref.current) {
40 | observer.observe(ref.current)
41 | }
42 |
43 | return () => {
44 | observer.disconnect()
45 | }
46 | }, [ref, onEnter])
47 |
48 | let slot = children
49 |
50 | if (placeholder && isChildVisible) {
51 | slot = placeholder
52 | }
53 |
54 | return (
55 | } data-testid="general-observer">
56 | {slot}
57 |
58 | )
59 | }
60 |
--------------------------------------------------------------------------------
/src/components/learnMore.tsx:
--------------------------------------------------------------------------------
1 | import generic from "../data/generic"
2 | import containerStyles from "../styles/container.module.css"
3 | import buttonStyles from "../styles/button.module.css"
4 | import { useRouter } from "next/router"
5 |
6 | export default function LearnMore() {
7 | const router = useRouter()
8 | return (
9 |
10 |
{generic.learnMore.title}
11 |
{generic.learnMore.description}
12 |
13 |
22 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/logic/getEditLink.tsx:
--------------------------------------------------------------------------------
1 | const preFix =
2 | "https://github.com/react-hook-form/documentation/edit/master/src/"
3 |
4 | const dataPreFix = "data/"
5 | const pagesPreFix = "pages/"
6 | const content = "content/"
7 |
8 | const filterApiPageURL = (pathname: string): string => {
9 | if (pathname.charAt(pathname.length - 1) === "/")
10 | return pathname.substring(0, pathname.length - 1).substring(1)
11 |
12 | return pathname.substring(1)
13 | }
14 |
15 | export const getEditLink = (pathname: string): string => {
16 | if (!pathname) return ""
17 |
18 | if (pathname === "/" || pathname === "") {
19 | return `${preFix}${dataPreFix}/home.tsx`
20 | } else if (pathname.includes("get-started")) {
21 | return `${preFix}${content}get-started.mdx`
22 | } else if (pathname.includes("api")) {
23 | const splitPath = pathname.split("/")
24 | if (splitPath.length === 2 || splitPath[2] === "") {
25 | return `${preFix}${dataPreFix}api.tsx`
26 | }
27 | return `${preFix}${pagesPreFix}${filterApiPageURL(pathname)}.tsx`
28 | } else if (pathname.includes("ts")) {
29 | return `${preFix}${content}ts.mdx`
30 | } else if (pathname.includes("advanced-usage")) {
31 | return `${preFix}${content}advanced.mdx`
32 | } else if (pathname.includes("faqs")) {
33 | return `${preFix}${content}faq.mdx`
34 | } else if (pathname.includes("dev-tools")) {
35 | return `${preFix}${dataPreFix}devtools.tsx`
36 | } else if (pathname.includes("form-builder")) {
37 | return `${preFix}${dataPreFix}builder.tsx`
38 | } else if (pathname.includes("resources")) {
39 | return `${preFix}${dataPreFix}resources.tsx`
40 | }
41 |
42 | return ""
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/mdx/code.tsx:
--------------------------------------------------------------------------------
1 | import { useMemo } from "react"
2 | import type { ReactNode } from "react"
3 | import { Highlight } from "prism-react-renderer"
4 | import { useTheme } from "next-themes"
5 | import { darkTheme, lightTheme } from "./theme"
6 |
7 | function usePrismTheme() {
8 | const { theme } = useTheme()
9 |
10 | return useMemo(() => {
11 | if (theme === "light") return lightTheme
12 | return darkTheme
13 | }, [theme])
14 | }
15 |
16 | export const PrismSyntaxHighlight = ({
17 | children,
18 | className,
19 | }: {
20 | children: ReactNode
21 | className: string
22 | }) => {
23 | const language = className.replace(/language-/gm, "")
24 |
25 | const currentTheme = usePrismTheme()
26 |
27 | return (
28 |
33 | {({ className, style, tokens, getLineProps, getTokenProps }) => (
34 |
35 | {tokens.map((line, lineIndex) => {
36 | const { key: lineKey, ...lineProps } = getLineProps({
37 | line,
38 | key: lineIndex,
39 | })
40 |
41 | return (
42 |
43 | {line.map((lineToken, linenTokenIndex) => {
44 | const { key: lineTokenKey, ...lineTokenProps } =
45 | getTokenProps({
46 | token: lineToken,
47 | key: linenTokenIndex,
48 | })
49 | return (
50 |
51 | )
52 | })}
53 |
54 | )
55 | })}
56 |
57 | )}
58 |
59 | )
60 | }
61 |
--------------------------------------------------------------------------------
/src/components/mdx/mdx.tsx:
--------------------------------------------------------------------------------
1 | import { PrismSyntaxHighlight } from "./code"
2 | import { Pre } from "./pre"
3 | import TabGroup from "../TabGroup"
4 | import { YouTube } from "./youtube"
5 | import TypeText from "../TypeText"
6 | import Popup from "../Popup"
7 | import { Components } from "@mdx-js/react/lib"
8 | import { Admonition } from "../Admonition"
9 | import { CodeSandBoxLink } from "../CodeSandbox"
10 | import tableStyles from "../../styles/table.module.css"
11 | import { SelectNav } from "@/components/selectNav"
12 | import CodeArea from "@/components/CodeArea"
13 |
14 | export const MDXComponents: Components = {
15 | // p: P,
16 | // strong: Strong,
17 | // blockquote: Blockquote,
18 | // ol: OL,
19 | // ul: UL,
20 | // li: LI,
21 | // h1: H1,
22 | // h2: H2,
23 | // h3: H3,
24 | // h4: H4,
25 | // hr: Divider,
26 | // a: Link,
27 | // img: ResponsiveImage,
28 | // Layout,
29 | SelectNav,
30 | CodeArea,
31 | table(props) {
32 | return (
33 |
36 | )
37 | },
38 | Admonition,
39 | Popup,
40 | TypeText,
41 | YouTube(props) {
42 | return
43 | },
44 | CodeSandbox: CodeSandBoxLink,
45 | pre(props) {
46 | return
47 | },
48 | code({ className, children, ...props }) {
49 | return className ? (
50 |
51 | {children}
52 |
53 | ) : (
54 | {children}
55 | )
56 | },
57 | TabGroup,
58 | PrettyObject({ value }: { value: Record }) {
59 | return JSON.stringify(value, null, 2).replace(/"/g, "")
60 | },
61 | }
62 |
--------------------------------------------------------------------------------
/src/components/mdx/pre.tsx:
--------------------------------------------------------------------------------
1 | import type { DetailedHTMLProps, HTMLAttributes } from "react"
2 | import { isValidElement, useRef } from "react"
3 | import ClipBoard from "../ClipBoard"
4 | import styles from "../CodeArea.module.css"
5 | import copyClipBoard from "../utils/copyClipBoard"
6 | import { CodeSandBoxLink } from "../CodeSandbox"
7 |
8 | export const Pre = (
9 | props: DetailedHTMLProps, HTMLPreElement> & {
10 | copy?: boolean
11 | sandbox?: string
12 | expo?: boolean
13 | }
14 | ) => {
15 | const preRef = useRef(null)
16 |
17 | const language = isValidElement<{ className?: string }>(props.children)
18 | ? props.children.props.className?.replace(/language-/gm, "") || ""
19 | : ""
20 |
21 | const isJs = language === "javascript"
22 |
23 | return (
24 |
29 |
30 | {props.copy && (
31 | {
34 | if (preRef.current?.innerText) {
35 | copyClipBoard(preRef.current.innerText)
36 | }
37 | }}
38 | />
39 | )}
40 | {props.sandbox && (
41 |
46 | )}
47 |
48 |
{props.children}
49 |
50 | )
51 | }
52 |
--------------------------------------------------------------------------------
/src/components/mdx/youtube.tsx:
--------------------------------------------------------------------------------
1 | import { FunctionComponent } from "react"
2 |
3 | import { GeneralObserver } from "../general-observer"
4 |
5 | interface YouTubeProps {
6 | /** YouTube id */
7 | youTubeId: string
8 |
9 | /** Auto play the video */
10 | autoPlay?: boolean
11 |
12 | /** No Cookie option */
13 | noCookie?: boolean
14 | }
15 |
16 | export const YouTube: FunctionComponent = (
17 | props: YouTubeProps
18 | ) => {
19 | const { youTubeId, autoPlay = false, noCookie = false } = props
20 |
21 | const provider = noCookie
22 | ? "https://www.youtube-nocookie.com"
23 | : "https://www.youtube.com"
24 |
25 | const src = `${provider}/embed/${youTubeId}?&autoplay=${autoPlay.toString()}`
26 |
27 | return (
28 |
29 |
39 |
40 | )
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/selectNav.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100%;
3 | margin-top: 1rem;
4 | background: none;
5 | appearance: none;
6 | color: var(--color-text);
7 | border: 1px solid var(--color-light-blue);
8 | border-radius: 3px;
9 | padding-left: 15px;
10 | padding-right: 15px;
11 | cursor: pointer;
12 | position: relative;
13 | }
14 |
15 | .root:hover {
16 | border: 1px solid var(--color-secondary);
17 | }
18 |
19 | .root > option {
20 | color: black;
21 | }
22 |
23 | @media (min-width: 768px) {
24 | .root {
25 | display: none;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/selectNav.tsx:
--------------------------------------------------------------------------------
1 | import styles from "./selectNav.module.css"
2 | import { useRouter } from "next/router"
3 |
4 | type Props = {
5 | options: {
6 | value: string
7 | label: string
8 | }[]
9 | }
10 |
11 | export function SelectNav({ options }: Props) {
12 | const router = useRouter()
13 |
14 | return (
15 | // eslint-disable-next-line jsx-a11y/no-onchange
16 |
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/seo.tsx:
--------------------------------------------------------------------------------
1 | import Head from "next/head"
2 |
3 | const site = {
4 | siteMetadata: {
5 | title: `React Hook Form - Simple React forms validation`,
6 | description: `Performant, flexible and extensible forms with easy-to-use validation.`,
7 | author: `@bluebill1049`,
8 | siteUrl: "https://www.react-hook-form.com",
9 | languages: {
10 | langs: ["en", "es", "jp", "zh", "kr", "pt", "ru"],
11 | defaultLangKey: "en",
12 | },
13 | },
14 | }
15 |
16 | function SEO({ title, description }: { title: string; description?: string }) {
17 | const metaDescription = description || site.siteMetadata.description
18 |
19 | return (
20 |
21 | {title || site.siteMetadata.title}
22 |
27 |
31 |
32 |
36 |
37 |
38 |
42 |
46 |
47 | )
48 | }
49 |
50 | export default SEO
51 |
--------------------------------------------------------------------------------
/src/components/sponsorsList.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | text-align: center;
3 | margin: 1rem 0 1rem 0;
4 | font-size: 0.8rem;
5 | border-top: 1px solid var(--color-black);
6 | padding-top: 1.5rem;
7 | }
8 |
9 | .heading {
10 | margin-bottom: 2rem;
11 | opacity: 0.7;
12 | font-weight: 500;
13 | }
14 |
15 | .root a {
16 | color: white;
17 | text-decoration: none;
18 | display: flex;
19 | align-content: center;
20 | justify-content: center;
21 | }
22 |
23 | .root a img {
24 | width: 120px;
25 | height: auto;
26 | margin: auto 0;
27 | }
28 |
29 | .logoGroup {
30 | display: grid;
31 | grid-template-columns: repeat(2, 1fr);
32 | gap: 1rem;
33 | margin: 0 1rem;
34 | }
35 |
36 | .logoGroup > div {
37 | border-radius: 4px;
38 | padding: 0.5rem;
39 | }
40 |
41 | .placeholder {
42 | border: 1px dashed #ccc;
43 | border-radius: 4px;
44 | padding: 0.5rem;
45 | }
46 |
47 | .twicsy {
48 | border-radius: 50px;
49 | }
50 |
51 | @media (min-width: 768px) {
52 | .logoGroup {
53 | display: grid;
54 | max-width: 600px;
55 | margin: 0 auto;
56 | grid-template-columns: repeat(4, 1fr);
57 | gap: 1.5rem;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/components/sponsorsList.tsx:
--------------------------------------------------------------------------------
1 | import styles from "./sponsorsList.module.css"
2 |
3 | export function SponsorsList() {
4 | return (
5 |
6 |
SUPPORTED AND BACKED BY
7 |
8 |
52 |
53 | )
54 | }
55 |
--------------------------------------------------------------------------------
/src/components/useForm/Register.tsx:
--------------------------------------------------------------------------------
1 | import Footer from "../Footer"
2 | import api from "../../data/api"
3 | import ApiRefTable from "../ApiRefTable"
4 | import typographyStyles from "../../styles/typography.module.css"
5 | import containerStyles from "../../styles/container.module.css"
6 | import StarRepo from "../StarRepo"
7 | import { Menu, apiLinks } from "../Menu"
8 |
9 | const Register = () => {
10 | return (
11 |
12 |
13 | register
14 |
15 |
16 | 비제어/제어 입력 필드 등록(register)
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | register:{" "}
27 | {`(name: string, RegisterOptions?) => ({ onChange, onBlur, name, ref })`}
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | )
43 | }
44 |
45 | export default Register
46 |
--------------------------------------------------------------------------------
/src/components/utils/copyClipBoard.ts:
--------------------------------------------------------------------------------
1 | export default function copyToClipboard(text: string) {
2 | return new Promise((resolve, reject) => {
3 | if (navigator?.clipboard) {
4 | const cb = navigator.clipboard
5 | cb.writeText(text).then(resolve).catch(reject)
6 | } else {
7 | try {
8 | const body = document.querySelector("body")
9 |
10 | const textarea = document.createElement("textarea")
11 | body?.appendChild(textarea)
12 |
13 | textarea.value = text
14 | textarea.select()
15 |
16 | document.execCommand("copy")
17 |
18 | body?.removeChild(textarea)
19 |
20 | resolve(0)
21 | } catch (e) {
22 | reject(e as Error)
23 | }
24 | }
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/utils/goToBuilder.ts:
--------------------------------------------------------------------------------
1 | export default function goToBuilder(toggle = true) {
2 | const title = " | React hook form - Simple React form validation"
3 |
4 | if (toggle) {
5 | document.title = `Form Builder${title}`
6 | window.history.pushState(
7 | { page: `Form Builder${title}` },
8 | `Form Builder${title}`,
9 | `/form-builder`
10 | )
11 | } else {
12 | document.title = `Home${title}`
13 | window.history.pushState({ page: `Home${title}` }, `Home${title}`, `/`)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/utils/useWindowSize.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react"
2 |
3 | interface Size {
4 | width: number
5 | height: number
6 | }
7 |
8 | export default function useWindowSize(): Size {
9 | const [windowSize, setWindowSize] = useState({
10 | width: 0,
11 | height: 0,
12 | })
13 |
14 | useEffect(() => {
15 | function handleResize() {
16 | setWindowSize({
17 | width: window.innerWidth,
18 | height: window.innerHeight,
19 | })
20 | }
21 |
22 | window.addEventListener("resize", handleResize)
23 |
24 | return () => {
25 | window.removeEventListener("resize", handleResize)
26 | }
27 | }, [])
28 |
29 | return windowSize
30 | }
31 |
--------------------------------------------------------------------------------
/src/content/docs/formprovider.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: FormProvider
3 | description: React 컨텍스트를 제공하는 컴포넌트
4 | sidebar: apiLinks
5 | ---
6 |
7 | 이 컴포넌트는 컨텍스트 객체를 제공하며, 컨텍스트를 사용하는 컴포넌트가 컨텍스트를 구독하고 [useForm](/docs/useform)의 props와 메서드를 사용할 수 있도록 합니다.
8 |
9 | ### Props
10 |
11 | ---
12 |
13 | 다음 테이블은 `FormProvider`에 적용되며, `useFormContext`는 인자를 받지 않습니다.
14 |
15 | | Name | Type | Description |
16 | | ---------- | --------------------------- | ------------------------------------------------------- |
17 | | `...props` | Object | `FormProvider`는 모든 `useForm` 메서드를 필요로 합니다. |
18 |
19 |
20 |
21 | - FormProvider를 중첩해서 사용하는 것을 피하세요
22 |
23 |
24 |
25 | **Examples:**
26 |
27 | ---
28 |
29 | ```javascript copy sandbox="https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi"
30 | import React from "react"
31 |
32 | import { useForm, FormProvider, useFormContext } from "react-hook-form"
33 |
34 | export default function App() {
35 | const methods = useForm()
36 |
37 | const onSubmit = (data) => console.log(data)
38 |
39 | return (
40 |
41 | // 모든 메서드를 컨텍스트에 전달
42 |
46 |
47 | )
48 | }
49 |
50 | function NestedInput() {
51 | const { register } = useFormContext() // 모든 훅 메서드를 가져옴
52 |
53 | return
54 | }
55 | ```
56 |
--------------------------------------------------------------------------------
/src/content/docs/useform/control.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: control
3 | description: 폼을 제어
4 | sidebar: apiLinks
5 | ---
6 |
7 | ## \> `control:` Object
8 |
9 | 이 객체는 컴포넌트를 리액트 훅 폼에 등록할 수 있는 메소드들을 포함합니다.
10 |
11 |
12 |
13 | **Important:** 직접 이 객체의 속성에 접근하지 마세요. 속성은 패키지 내부 용도로만 사용합니다.
14 |
15 |
16 |
17 | **Examples:**
18 |
19 | ---
20 |
21 |
22 |
23 | ```typescript copy sandbox="https://codesandbox.io/s/react-hook-form-v6-controller-ts-jwyzw"
24 | import React from "react"
25 | import { useForm, Controller } from "react-hook-form"
26 | import { TextField } from "@material-ui/core"
27 |
28 | type FormInputs = {
29 | firstName: string
30 | }
31 |
32 | function App() {
33 | const { control, handleSubmit } = useForm()
34 | const onSubmit = (data: FormInputs) => console.log(data)
35 |
36 | return (
37 |
47 | )
48 | }
49 | ```
50 |
51 | ```javascript copy sandbox="https://codesandbox.io/s/react-hook-form-v7-controller-5h1q5"
52 | import { useForm, Controller } from "react-hook-form"
53 |
54 | function App() {
55 | const { control } = useForm()
56 |
57 | return (
58 | }
60 | name="firstName"
61 | control={control}
62 | defaultValue=""
63 | />
64 | )
65 | }
66 | ```
67 |
68 |
69 |
--------------------------------------------------------------------------------
/src/content/docs/useformcontext.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: useFormContext
3 | description: 훅 폼을 위한 React Context API
4 | sidebar: apiLinks
5 | ---
6 |
7 | ## \> `useFormContext:` Function
8 |
9 | 이 커스텀 훅은 폼 컨텍스트에 접근할 수 있게 해줍니다. `useFormContext`는 깊게 중첩된 구조에서 컨텍스트를 props로 전달하는 것이 불편할 때 사용하도록 설계되었습니다.
10 |
11 | ### Return
12 |
13 | ---
14 |
15 | 이 훅은 useForm이 반환하는 모든 메서드와 props를 반환합니다.
16 |
17 | ```javascript
18 | const methods = useForm()
19 |
20 | // useForm이 반환하는 모든 props
21 |
22 | const methods = useFormContext() // 해당 props를 가져옴
23 | ```
24 |
25 |
26 | `useFormContext`가 제대로 작동하려면, 먼저 폼을
27 | [`FormProvider`](/docs/formprovider) 컴포넌트로 감싸야 합니다.
28 |
29 |
30 | **Example:**
31 |
32 | ```javascript copy codesandbox="https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi"
33 | import React from "react"
34 | import { useForm, FormProvider, useFormContext } from "react-hook-form"
35 |
36 | export default function App() {
37 | const methods = useForm()
38 | const onSubmit = (data) => console.log(data)
39 |
40 | return (
41 |
42 | // 모든 메서드를 컨텍스트에 전달
43 |
47 |
48 | )
49 | }
50 |
51 | function NestedInput() {
52 | const { register } = useFormContext() // 모든 훅 메서드를 가져옴
53 | return
54 | }
55 | ```
56 |
--------------------------------------------------------------------------------
/src/data/builder.tsx:
--------------------------------------------------------------------------------
1 | export default {
2 | title: "Form Builder",
3 | description: "GUI for building forms with validation",
4 | builder: {
5 | title: "Form Builder",
6 | description: "Build your form with code and example.",
7 | },
8 | layout: {
9 | title: "Layout",
10 | message: "You can start adding fields with Input Creator.",
11 | },
12 | inputCreator: {
13 | title: "Input Creator",
14 | description: `This form allows you to create and update inputs. The Generate Form button will create a new form with the updates.`,
15 | message: "You can start adding fields with Input Creator.",
16 | options: "Options",
17 | validation: "Show validation",
18 | generate: "Generate Form",
19 | },
20 | code: {
21 | title: "Code",
22 | description: `As you are making changes over the form, the code section will be updated and you can copy the code as well.`,
23 | },
24 | }
25 |
--------------------------------------------------------------------------------
/src/data/generic.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link"
2 |
3 | export default {
4 | copy: "Copy",
5 | codeCopied: "Copied",
6 | required: "Required",
7 | learnMore: {
8 | title: "Want to learn more?",
9 | description:
10 | "Check out the React Hook Form documentation and learn all about the API.",
11 | buttonText: "Checkout API",
12 | },
13 | advanceUsage: {
14 | title: "Advanced Usage",
15 | description: `Learn how to build complex and accessible forms`,
16 | buttonText: `Learn Advanced Usage`,
17 | },
18 | needYourSupport: {
19 | title: "지원해 주셔서 감사합니다",
20 | description:
21 | "프로젝트에서 React Hook Form이 유용하다고 생각하신다면, 스타를 눌러 지원해 주시길 부탁드립니다.",
22 | buttonText: "GitHub에서 스타 누르기",
23 | },
24 | codeExample: "Code Examples",
25 | menu: "Menu",
26 | note: "Note",
27 | select: "Select",
28 | name: "Name",
29 | type: "Type",
30 | default: "Default",
31 | description: "Description",
32 | features: "Features",
33 | delete: "Delete",
34 | example: "Example",
35 | edit: "수정",
36 | cancelEdit: "Cancel Edit",
37 | deleteAll: "Delete All",
38 | create: "Create",
39 | update: "Update",
40 | copied: "Copy code into your clipboard.",
41 | return: "Return",
42 | blog: "Articles/Blog",
43 | video: "Videos",
44 | newsletter: "Newsletter",
45 | binding: "3rd Party Bindings",
46 | liveDemo: "라이브 데모",
47 | control: (
48 | <>
49 | useForm
에서 제공하는{" "}
50 |
51 | control
52 | {" "}
53 | 객체. FormProvider를 사용하고 있다면 선택 사항입니다.
54 | >
55 | ),
56 | }
57 |
--------------------------------------------------------------------------------
/src/data/nav.tsx:
--------------------------------------------------------------------------------
1 | const Nav = {
2 | home: "Home",
3 | getStarted: "Get Started",
4 | advanced: "Advanced",
5 | tools: {
6 | nav: "Tools",
7 | devTools: "DevTools",
8 | formBuilder: "Form Builder",
9 | },
10 | builder: (
11 | <>
12 | Form Builder
13 | >
14 | ),
15 | faqs: "FAQs",
16 | releases: "Releases",
17 | resources: "Resources",
18 | }
19 |
20 | export default Nav
21 |
--------------------------------------------------------------------------------
/src/pages/404.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | padding: 2rem;
3 | }
4 |
5 | .root {
6 | text-align: center;
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/404.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../components/layout"
2 | import Seo from "../components/seo"
3 | import styles from "./404.module.css"
4 |
5 | const NotFoundPage = () => (
6 |
7 |
8 |
9 |
10 | NOT FOUND
11 | You just found a route that doesn't exist... the sadness.
12 |
13 |
14 |
15 | )
16 |
17 | export default NotFoundPage
18 |
--------------------------------------------------------------------------------
/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import { StateMachineProvider, createStore } from "little-state-machine"
2 | import { type AppProps } from "next/app"
3 | import Head from "next/head"
4 | import formData from "../state/formData"
5 | import { ThemeProvider } from "next-themes"
6 | import { useEffect } from "react"
7 | import "../components/layout.css"
8 | import PostHogProvider from "./providers/PostHogProvider"
9 |
10 | createStore(
11 | {
12 | formData,
13 | },
14 | {
15 | storageType:
16 | typeof window !== "undefined" ? window.localStorage : undefined,
17 | }
18 | )
19 |
20 | function App({ Component, pageProps }: AppProps) {
21 | useEffect(() => {
22 | try {
23 | if (window.navigator && navigator.serviceWorker) {
24 | navigator.serviceWorker
25 | .getRegistrations()
26 | .then(function (registrations) {
27 | if (Array.isArray(registrations)) {
28 | for (const registration of registrations) {
29 | registration.unregister()
30 | }
31 | }
32 | })
33 | }
34 | } catch {}
35 | }, [])
36 |
37 | return (
38 | <>
39 |
40 | React Hook Form - Simple React forms validation
41 |
45 |
46 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | >
58 | )
59 | }
60 |
61 | export default App
62 |
--------------------------------------------------------------------------------
/src/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from "next/document"
2 | import Script from "next/script"
3 |
4 | export default function Document() {
5 | return (
6 |
7 |
8 |
12 |
16 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/src/pages/dev-tools.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../components/layout"
2 | import Seo from "../components/seo"
3 | import DevTools from "../components/DevTools"
4 | import api from "../data/api"
5 |
6 | const Api = () => (
7 |
8 |
9 |
10 |
11 | )
12 |
13 | export default Api
14 |
--------------------------------------------------------------------------------
/src/pages/docs.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../components/layout"
2 | import Seo from "../components/seo"
3 | import api from "../data/api"
4 | import ApiGallery from "../components/ApiGallery"
5 |
6 | const Api = () => (
7 |
8 |
9 |
10 |
11 | )
12 |
13 | export default Api
14 |
--------------------------------------------------------------------------------
/src/pages/docs/usecontroller.tsx:
--------------------------------------------------------------------------------
1 | import Seo from "../../components/seo"
2 | import Layout from "../../components/layout"
3 | import UseControllerContent from "../../components/UseController"
4 |
5 | export default function Usecontroller() {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/src/pages/docs/usefieldarray.tsx:
--------------------------------------------------------------------------------
1 | import Seo from "../../components/seo"
2 | import Layout from "../../components/layout"
3 | import UseFieldArrayContent from "../../components/UseFieldArray"
4 |
5 | export default function UseFieldArray() {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/src/pages/form-builder.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../components/layout"
2 | import Seo from "../components/seo"
3 | import BuilderPage from "../components/BuilderPage"
4 | import builder from "../data/builder"
5 |
6 | const Api = () => {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
15 | export default Api
16 |
--------------------------------------------------------------------------------
/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../components/layout"
2 | import Seo from "../components/seo"
3 | import Home from "../components/HomePage"
4 | import home from "../data/home"
5 |
6 | const IndexPage = () => (
7 |
8 |
9 |
10 |
11 | )
12 |
13 | export default IndexPage
14 |
--------------------------------------------------------------------------------
/src/pages/media.module.css:
--------------------------------------------------------------------------------
1 | .media {
2 | max-width: 800px;
3 | margin: 3rem auto;
4 | display: flex;
5 | flex-direction: column;
6 | grid-template-columns: 1fr 1fr;
7 | gap: 2rem;
8 | }
9 |
10 | .media div {
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | }
15 |
16 | .media p {
17 | font-size: 12px;
18 | }
19 |
20 | .media img {
21 | width: 100%;
22 | border-radius: 10px;
23 | }
24 |
25 | img.logo {
26 | width: 200px;
27 | height: 200px;
28 | }
29 |
30 | @media (min-width: 768px) {
31 | .media {
32 | margin: 3rem auto;
33 | display: grid;
34 | grid-template-columns: 1fr 1fr;
35 | gap: 2rem;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/pages/migrate-v6-to-v7.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react"
2 |
3 | export default function MigrateV6ToV7() {
4 | useEffect(() => {
5 | window.location.href = "https://legacy.react-hook-form.com/migrate-v6-to-v7"
6 | }, [])
7 |
8 | return null
9 | }
10 |
--------------------------------------------------------------------------------
/src/pages/providers/PostHogProvider.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react"
2 | import posthog from "posthog-js"
3 | import { Router } from "next/router"
4 | import { PostHogProvider as PostHogProviderBase } from "posthog-js/react"
5 |
6 | interface PostHogProviderProps {
7 | children: React.ReactNode
8 | }
9 |
10 | const PostHogProvider = ({ children }: PostHogProviderProps) => {
11 | useEffect(() => {
12 | posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY as string, {
13 | api_host:
14 | process.env.NEXT_PUBLIC_POSTHOG_HOST || "https://us.i.posthog.com",
15 | person_profiles: "identified_only",
16 | loaded: (posthog) => {
17 | if (process.env.NODE_ENV === "development") posthog.debug()
18 | },
19 | })
20 |
21 | const handleRouteChange = () => posthog?.capture("$pageview")
22 |
23 | Router.events.on("routeChangeComplete", handleRouteChange)
24 |
25 | return () => {
26 | Router.events.off("routeChangeComplete", handleRouteChange)
27 | }
28 | }, [])
29 | return {children}
30 | }
31 |
32 | export default PostHogProvider
33 |
--------------------------------------------------------------------------------
/src/pages/resources/3rd-party-bindings.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../../components/layout"
2 | import Seo from "../../components/seo"
3 | import ResourcePageBindings from "../../components/ResourcePageBindings"
4 |
5 | const ResourcesBindings = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default ResourcesBindings
15 |
--------------------------------------------------------------------------------
/src/pages/resources/articles.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../../components/layout"
2 | import Seo from "../../components/seo"
3 | import ResourcePageArticles from "../../components/ResourcePageArticles"
4 |
5 | const ResourcesArticles = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default ResourcesArticles
15 |
--------------------------------------------------------------------------------
/src/pages/resources/newsletters.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../../components/layout"
2 | import Seo from "../../components/seo"
3 | import ResourcePageNewsletter from "../../components/ResourcePageNewsletter"
4 |
5 | const ResourcesNewsletter = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default ResourcesNewsletter
15 |
--------------------------------------------------------------------------------
/src/pages/resources/videos.tsx:
--------------------------------------------------------------------------------
1 | import Layout from "../../components/layout"
2 | import Seo from "../../components/seo"
3 | import ResourcePageVideos from "../../components/ResourcePageVideos"
4 |
5 | const ResourcesVideos = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default ResourcesVideos
15 |
--------------------------------------------------------------------------------
/src/react-ko-form/components/Banner.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | position: relative;
3 | display: flex;
4 | align-items: center;
5 | justify-content: center;
6 | background-color: #000;
7 | padding: 8px 16px;
8 | height: 60px;
9 | }
10 |
11 | .link {
12 | display: block;
13 | margin: 0 auto;
14 | max-width: calc(100% - 267px);
15 | color: #fff;
16 | text-decoration: none;
17 | text-align: center;
18 | white-space: normal;
19 | word-break: break-word;
20 | overflow: hidden;
21 | }
22 |
23 | @media (max-width: 767px) {
24 | .container {
25 | position: static;
26 | margin-top: 60px;
27 | height: auto;
28 | padding: 8px 16px;
29 | }
30 |
31 | .link {
32 | position: static;
33 | transform: none;
34 | left: auto;
35 | max-width: none;
36 | white-space: normal;
37 | word-break: break-word;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/react-ko-form/components/Banner.tsx:
--------------------------------------------------------------------------------
1 | import styles from "./Banner.module.css"
2 |
3 | export const Banner = () => {
4 | return (
5 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/src/state/formData.ts:
--------------------------------------------------------------------------------
1 | import type { GlobalState } from "little-state-machine"
2 |
3 | const formData: GlobalState["formData"] = [
4 | {
5 | name: "First name",
6 | type: "text",
7 | required: true,
8 | max: "",
9 | min: "",
10 | maxLength: "80",
11 | minLength: "",
12 | pattern: "",
13 | },
14 | {
15 | name: "Last name",
16 | type: "text",
17 | required: true,
18 | max: "",
19 | min: "",
20 | maxLength: "100",
21 | minLength: "",
22 | pattern: "",
23 | },
24 | {
25 | name: "Email",
26 | type: "text",
27 | required: true,
28 | max: "",
29 | min: "",
30 | maxLength: "",
31 | minLength: "",
32 | pattern: "^\\S+@\\S+$",
33 | },
34 | {
35 | name: "Mobile number",
36 | type: "tel",
37 | required: true,
38 | max: "",
39 | min: "",
40 | maxLength: "12",
41 | minLength: "6",
42 | pattern: "",
43 | },
44 | {
45 | name: "Title",
46 | type: "select",
47 | required: true,
48 | max: "",
49 | min: "",
50 | maxLength: "",
51 | minLength: "",
52 | pattern: "",
53 | options: "Mr;Mrs;Miss;Dr",
54 | },
55 | {
56 | name: "Developer",
57 | type: "radio",
58 | required: true,
59 | max: "",
60 | min: "",
61 | maxLength: "",
62 | minLength: "",
63 | pattern: "",
64 | options: "Yes;No",
65 | },
66 | ]
67 |
68 | export default formData
69 |
--------------------------------------------------------------------------------
/src/styles/breakpoints.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | fromXsmallScreen: "(min-width: 320px)",
3 | fromSmallScreen: "(min-width: 480px)",
4 | fromMediumScreen: "(min-width: 768px)",
5 | fromLargeScreen: "(min-width: 1024px)",
6 | fromXlargeScreen: "(min-width: 1280px)",
7 | fromXxlargeScreen: "(min-width: 1600px)",
8 | }
9 |
10 | export const LARGE_SCREEN = 1600
11 |
--------------------------------------------------------------------------------
/src/styles/colors.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | primary: "#0e101c",
3 | secondary: "#bf1650",
4 | lightBlue: "#516391",
5 | blue: "#1e2a4a",
6 | lightPink: "#ec5990",
7 | errorPink: "#fbecf2",
8 | buttonBlue: "#191d3a",
9 | link: "#ff7aa8",
10 | black: "#000",
11 | }
12 |
--------------------------------------------------------------------------------
/src/styles/container.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | padding-top: 45px;
3 | }
4 |
5 | .subContainer {
6 | margin: 0 auto;
7 | max-width: 768px;
8 | }
9 |
10 | .centerContent {
11 | margin: 0 auto;
12 | text-align: center;
13 | max-width: 1024px;
14 | }
15 |
16 | .centerContent svg {
17 | display: none;
18 | }
19 |
20 | .wrapper {
21 | max-width: 1235px;
22 | margin: 0 auto;
23 | overflow: hidden;
24 | position: relative;
25 | padding: 0 15px 50px 20px;
26 | }
27 |
28 | .centerContent p {
29 | max-width: 730px;
30 | margin: 0 auto 0;
31 | }
32 |
33 | .centerContent h3 {
34 | margin: 0;
35 | }
36 |
37 | @media (min-width: 768px) {
38 | .container {
39 | padding-top: 0;
40 | }
41 |
42 | .centerContent svg {
43 | width: 85px;
44 | display: block;
45 | text-align: center;
46 | margin: 100px auto -30px;
47 | }
48 |
49 | .wrapper {
50 | display: grid;
51 | grid-template-columns: 250px minmax(0, 1fr);
52 | }
53 | }
54 |
55 | @media (min-width: 1024px) {
56 | .wrapper {
57 | display: grid;
58 | grid-template-columns: 300px minmax(0, 1fr);
59 | }
60 |
61 | .centerContent svg {
62 | margin: 100px auto -50px;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/styles/table.module.css:
--------------------------------------------------------------------------------
1 | .table {
2 | border-collapse: collapse;
3 | width: 100%;
4 | }
5 |
6 | .table td {
7 | padding: 6px 15px 6px 0;
8 | line-height: 1.4;
9 | font-size: 0.875rem;
10 | }
11 |
12 | .table td > h5:first-child,
13 | .table td > p:first-child,
14 | .table td > ul:first-child,
15 | .table td > ul li:first-child > p {
16 | margin-top: 0 !important;
17 | }
18 |
19 | .table td > ul li {
20 | margin: 0.5rem 0;
21 | }
22 |
23 | .table td > ul li:first-child {
24 | margin-top: 0;
25 | }
26 |
27 | .table td > ul li:last-child {
28 | margin-bottom: 0;
29 | }
30 |
31 | .table td:last-child {
32 | padding-right: 0;
33 | }
34 |
35 | .tableWrapper {
36 | -webkit-overflow-scrolling: touch;
37 | overflow-y: hidden;
38 | overflow-x: auto;
39 | }
40 |
41 | @media (min-width: 768px) {
42 | .mobileTypeText {
43 | margin-top: 0px;
44 | display: inline;
45 | }
46 |
47 | .tableWrapper::-webkit-scrollbar {
48 | height: 8px;
49 | }
50 |
51 | .tableWrapper::-webkit-scrollbar-track {
52 | background: var(--color-button-blue);
53 | border-radius: 10px;
54 | }
55 |
56 | .tableWrapper::-webkit-scrollbar-thumb {
57 | background: var(--color-medium-blue);
58 | border-radius: 10px;
59 | }
60 |
61 | .tableWrapper::-webkit-scrollbar-thumb:hover {
62 | background: var(--color-light-pink);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/types/global.d.ts:
--------------------------------------------------------------------------------
1 | interface Window {
2 | docsearch?: (options: {
3 | appId: string
4 | apiKey: string
5 | indexName: string
6 | inputSelector: string
7 | }) => vod
8 | }
9 |
10 | declare module "*.mdx" {
11 | export const meta: {
12 | title: string
13 | description: string
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/types/little-state-machine.d.ts:
--------------------------------------------------------------------------------
1 | import "little-state-machine"
2 |
3 | declare module "little-state-machine" {
4 | export interface FormDataItem {
5 | name: string
6 | type: string
7 | required: boolean
8 | max: string
9 | min: string
10 | maxLength: string
11 | minLength: string
12 | pattern: string
13 | /** Available when type is `select` or `radio` */
14 | options?: string
15 | }
16 |
17 | interface GlobalState {
18 | formData: FormDataItem[]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/types/types.ts:
--------------------------------------------------------------------------------
1 | export type Pages = {
2 | pathname: string
3 | name: string
4 | pages?: {
5 | pathname: string
6 | name: string
7 | }[]
8 | }[]
9 |
--------------------------------------------------------------------------------