├── .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 |
2 |

3 | 4 | React Hook Form Logo - React hook custom hook for form validation 5 | 6 |

7 |
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 | 20 | 21 | 25 | 26 | 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 | 18 | 19 | 20 | 21 | 22 | 23 |
{generic.name}{generic.type}{generic.description}
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 |
42 | { 53 | setFocus(true) 54 | }} 55 | onBlur={() => { 56 | if (LARGE_SCREEN > width) { 57 | setFocus(false) 58 | } 59 | }} 60 | /> 61 | {!focus && } 62 | 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 |
23 | 24 | 25 | 26 |
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 |
21 | 22 | 23 | 24 |
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 |
31 | 32 | 33 | 34 | 35 | 36 | 45 |
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 |
console.log(d))}> 12 |

React Hook Form DevTools

13 | 14 | 15 | 16 | 17 | 18 |
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 |
15 | 16 | 17 |
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 |
18 | 19 | 20 |
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 |
19 | 20 | 21 |
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 |
20 | 21 | 22 |
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 |
9 | 19 | {errors.email && errors.email.message} 20 | 21 | value !== "admin" || "Nice try!" 24 | })} 25 | /> 26 | {errors.username && errors.username.message} 27 | 28 | 29 |
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 |
32 | 33 | 34 |
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 |
console.log(data))}> 15 |
    16 | {fields.map((item, index) => ( 17 |
  • 18 | 19 | } 21 | name={\`test.\${index}.lastName\`} 22 | control={control} 23 | /> 24 | 25 |
  • 26 | ))} 27 |
28 | 34 | 35 |
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 |
51 | {fields.map((data, index) => ( 52 | <> 53 | 54 | 55 | 56 | ))} 57 | 58 | 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 |
19 | {fields.map((field, i) => ( 20 | 21 | ))} 22 | 28 | 34 |
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 |
console.log(data))}> 13 | {fields.map((field, index) => ( 14 | 21 | ))} 22 | 23 | 31 | 32 | 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 |
22 | 23 | 24 | 25 | 26 | 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 |
34 | 35 | 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 |