diff --git a/.browserslistrc b/.browserslistrc deleted file mode 100644 index 93cda006d..000000000 --- a/.browserslistrc +++ /dev/null @@ -1,3 +0,0 @@ -> 0.25% -ie 11 -not op_mini all diff --git a/.eslintrc.js b/.eslintrc.js index 9c85a039d..94b66c9b7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -41,5 +41,6 @@ module.exports = { "react/jsx-curly-brace-presence": "warn", // jsx-ally "jsx-a11y/no-onchange": WARN, + "import/no-anonymous-default-export": OFF, }, } diff --git a/.gitignore b/.gitignore index 38852b979..e22fc24f3 100755 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,7 @@ yarn-error.log* package-lock.json .vscode tsconfig.tsbuildinfo -.next/ \ No newline at end of file +.next/ + +# contentlayer +.contentlayer diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 000000000..d24fdfc60 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx lint-staged diff --git a/.lighthouserc.js b/.lighthouserc.js deleted file mode 100644 index 66dbfb720..000000000 --- a/.lighthouserc.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - collect: { - autodiscoverUrlBlocklist: ["_gatsby/slices/_gatsby-scripts-1.html"], - }, - ci: { - upload: { - target: "temporary-public-storage", - }, - assert: { - assertions: { - "first-contentful-paint": ["error", { maxNumericValue: 3000 }], - }, - }, - }, -} diff --git a/contentlayer.config.ts b/contentlayer.config.ts new file mode 100644 index 000000000..1c3a39456 --- /dev/null +++ b/contentlayer.config.ts @@ -0,0 +1,54 @@ +import { defineDocumentType, makeSource } from "contentlayer/source-files" +import { remarkHeadingId } from "remark-custom-heading-id" +import remarkGfm from "remark-gfm" +import rehypeMdxCodeProps from "rehype-mdx-code-props" +import emoji from "remark-emoji" +import * as sidebar from "./src/components/Menu/MenuLinks" + +export const Doc = defineDocumentType(() => ({ + name: "Doc", + contentType: "mdx", + filePathPattern: "**/*.mdx", + fields: { + title: { type: "string", required: true }, + description: { type: "string", required: true }, + sidebar: { + type: "enum", + options: [ + "apiLinks", + "advancedLinks", + "tsLinks", + "faqLinks", + "getStartedLinks", + ], + required: true, + }, + }, + computedFields: { + slug: { + type: "string", + resolve: (doc) => `/${doc._raw.flattenedPath}`, + }, + slugAsParams: { + type: "string", + resolve: (doc) => doc._raw.flattenedPath.split("/").slice(1).join("/"), + }, + segment: { + type: "list", + resolve: (doc) => doc._raw.flattenedPath.split("/"), + }, + pages: { + type: "list", + resolve: (doc) => sidebar[doc.sidebar] ?? [], + }, + }, +})) + +export default makeSource({ + contentDirPath: "src/content", + documentTypes: [Doc], + mdx: { + remarkPlugins: [remarkGfm, remarkHeadingId, emoji], + rehypePlugins: [rehypeMdxCodeProps], + }, +}) diff --git a/next.config.mjs b/next.config.mjs index 032a7ac5d..1a5fcfa54 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,9 +1,4 @@ -import withMDX from "@next/mdx" -import { remarkHeadingId } from "remark-custom-heading-id" -import remarkGfm from "remark-gfm" -import rehypeMdxCodeProps from "rehype-mdx-code-props" -import emoji from "remark-emoji" - +import { withContentlayer } from "next-contentlayer" import withBundleAnalyzer from "@next/bundle-analyzer" /** @type {import('next').NextConfig} */ @@ -19,14 +14,4 @@ const bundleAnalyzer = withBundleAnalyzer({ enabled: process.env.ANALYZE === "true", }) -export default bundleAnalyzer( - withMDX({ - extension: /\.mdx?$/, - options: { - remarkPlugins: [remarkGfm, remarkHeadingId, emoji], - rehypePlugins: [rehypeMdxCodeProps], - // If you use `MDXProvider`, uncomment the following line. - providerImportSource: "@mdx-js/react", - }, - })(nextConfig) -) +export default bundleAnalyzer(withContentlayer(nextConfig)) diff --git a/package.json b/package.json index 2e64791dd..f3223c59d 100644 --- a/package.json +++ b/package.json @@ -4,48 +4,50 @@ "version": "6.0.1", "author": "beier luo", "dependencies": { - "@hookform/devtools": "2.0.0-beta.1", + "@hookform/devtools": "4.3.1", "@mdx-js/loader": "^2.3.0", "@mdx-js/react": "^2.3.0", - "@next/mdx": "^13.4.4", - "@types/node": "^20.2.5", + "@next/mdx": "^13.4.5", + "@types/node": "^20.3.1", + "class-variance-authority": "^0.6.0", "clsx": "^1.2.1", + "contentlayer": "^0.3.3", + "date-fns": "^2.30.0", "little-state-machine": "^4.8.0", - "next": "^13.4.4", + "next": "^13.4.5", + "next-contentlayer": "^0.3.3", "next-themes": "^0.2.1", - "prism-react-renderer": "^2.0.4", + "prism-react-renderer": "^2.0.5", "prismjs": "^1.29.0", "react": "18.2.0", "react-dom": "18.2.0", "react-github-btn": "1.4.0", - "react-helmet": "6.1.0", - "react-hook-form": "6.0.0", + "react-hook-form": "7.44.3", "react-simple-animate": "^3.5.2", "react-simple-img": "3.0.0", "react-sortablejs": "1.5.1", - "react-syntax-highlighter": "^15.5.0", "rehype-mdx-code-props": "^1.0.0", "remark-custom-heading-id": "^1.0.1", - "remark-emoji": "^3.1.1", + "remark-emoji": "^3.1.2", "remark-gfm": "^3.0.1", "sortablejs": "1.15.0" }, "devDependencies": { - "@next/bundle-analyzer": "^13.4.4", + "@next/bundle-analyzer": "^13.4.5", "@types/react-helmet": "^6.1.6", - "@typescript-eslint/eslint-plugin": "^5.59.8", - "@typescript-eslint/parser": "^5.59.8", + "@typescript-eslint/eslint-plugin": "^5.59.11", + "@typescript-eslint/parser": "^5.59.11", "cross-env": "^7.0.3", - "eslint": "^8.41.0", - "eslint-config-next": "^13.4.4", + "eslint": "^8.42.0", + "eslint-config-next": "^13.4.5", "eslint-config-prettier": "^8.8.0", "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", - "husky": "^4.3.8", - "lint-staged": "^10.5.4", + "husky": "^8.0.3", + "lint-staged": "^13.2.2", "prettier": "^2.8.8", - "typescript": "^5.0.4" + "typescript": "^5.1.3" }, "keywords": [ "react-hook-form", @@ -56,19 +58,15 @@ "analyze": "cross-env ANALYZE=true next build", "build": "next build", "dev": "next dev", - "format": "prettier --write \"src/**/*.{ts,tsx,mdx}\"", + "format": "prettier --write", "lint": "next lint --fix", "now-build": "npm run build", - "start": "npm run develop", - "typecheck": "tsc --noEmit" - }, - "husky": { - "hooks": { - "pre-commit": "lint-staged" - } + "start": "next start", + "typecheck": "tsc --noEmit", + "prepare": "husky install" }, "lint-staged": { - "*.{ts,tsx,mdx}": [ + "*.{ts,tsx,mdx,css,json}": [ "npm run format" ] } diff --git a/src/actions/settingActions.ts b/src/actions/settingActions.ts deleted file mode 100644 index 9bc2a33e3..000000000 --- a/src/actions/settingActions.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { GlobalState } from "little-state-machine" - -export function updateSetting( - state: GlobalState, - payload: Partial -) { - return { - ...state, - setting: { - ...state.setting, - ...payload, - }, - } -} diff --git a/src/components/Admonition.module.css b/src/components/Admonition.module.css new file mode 100644 index 000000000..219194cf5 --- /dev/null +++ b/src/components/Admonition.module.css @@ -0,0 +1,59 @@ +.admonition { + margin-top: 1rem; + margin-bottom: 1em; + padding: 15px 30px 15px 15px; + border-radius: 0.4rem; +} + +.admonitionIcon { + display: inline-block; + vertical-align: middle; + margin-right: 0.2em; +} + +.admonitionIcon svg { + display: inline-block; + width: 22px; + height: 22px; + stroke-width: 0; +} + +.admonitionIcon svg { + stroke: rgb(253, 253, 254); + fill: rgb(253, 253, 254); +} + +.admonitionContent > :last-child { + margin-bottom: 0; +} + +/** Customization */ +.admonitionWarning { + background-color: rgba(230, 126, 34, 0.1); + border-left: 8px solid var(--color-orange); +} + +.admonitionTip { + background-color: rgba(46, 204, 113, 0.1); + border-left: 8px solid var(--color-green); +} + +.admonitionCaution { + background-color: rgba(231, 76, 60, 0.1); + border-left: 8px solid var(--color-secondary); +} + +.admonitionImportant { + background-color: rgb(25, 60, 71, 0.1); + border-left: 8px solid var(--color-blue); +} + +.admonitionNote { + background-color: rgb(71, 71, 72, 0.1); + border-left: 8px solid var(--color-text); +} + +.admonitionQuestion { + background-color: rgba(8, 61, 119, 0.1); + border-left: 8px solid var(--color-light-blue); +} diff --git a/src/components/Admonition.tsx b/src/components/Admonition.tsx new file mode 100644 index 000000000..edb3fd063 --- /dev/null +++ b/src/components/Admonition.tsx @@ -0,0 +1,113 @@ +import styles from "./Admonition.module.css" +import { cva } from "class-variance-authority" + +/** + * Octicons Icons by GitHub released under MIT License + * https://github.com/primer/octicons/ + */ + +const svgMap = { + warning: ( + + + + ), + important: ( + + + + ), + caution: ( + + + + ), + tip: ( + + + + ), + note: ( + + + + ), + question: ( + + + + ), +} + +const admonition = cva(styles.admonition, { + variants: { + type: { + warning: styles.admonitionWarning, + important: styles.admonitionImportant, + caution: styles.admonitionCaution, + tip: styles.admonitionTip, + note: styles.admonitionNote, + question: styles.admonitionQuestion, + }, + }, +}) + +export const Admonition = ({ type, title, children }) => { + return ( +
+
+ {svgMap[type]}{" "} + {title?.toUpperCase() || type.toUpperCase()} +
+
{children}
+
+ ) +} diff --git a/src/components/AdvancedPage.tsx b/src/components/AdvancedPage.tsx deleted file mode 100644 index 8d56dfa8f..000000000 --- a/src/components/AdvancedPage.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import Footer from "./Footer" -import StarRepo from "./StarRepo" -import typographyStyles from "../styles/typography.module.css" -import containerStyles from "../styles/container.module.css" -import AdvancedContent, { meta } from "../content/advanced.mdx" -import NewSideMenu from "./NewSideMenu" - -const links = [ - { - title: "Accessibility (A11y)", - href: "#AccessibilityA11y", - }, - { - title: "Wizard Form / Funnel", - href: "#WizardFormFunnel", - }, - { - title: "Smart Form Component", - href: "#SmartFormComponent", - }, - { - title: "Error Messages", - href: "#ErrorMessages", - }, - { - title: "Connect Form", - href: "#ConnectForm", - }, - { - title: "FormProvider Performance", - href: "#FormProviderPerformance", - }, - { - title: "Controlled mixed with Uncontrolled Components", - href: "#ControlledmixedwithUncontrolledComponents", - }, - { - title: "Custom Hook with Resolver", - href: "#CustomHookwithResolver", - }, - { - title: "Working with virtualized lists", - href: "#Workingwithvirtualizedlists", - }, - { - title: "Testing Form", - href: "#TestingForm", - }, - { - title: "Transform and Parse", - href: "#TransformandParse", - }, -] - -function Advanced() { - return ( -
-

- {meta.title} -

-

{meta.description}

- -
- - -
- - - -
-
-
-
- ) -} - -export default Advanced diff --git a/src/components/ApiErrors.tsx b/src/components/ApiErrors.tsx deleted file mode 100644 index 4f45159a2..000000000 --- a/src/components/ApiErrors.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { memo } from "react" -import CodeArea from "./CodeArea" -import errorCode from "./codeExamples/errorCode" -import errorCodeTs from "./codeExamples/errorCodeTs" -import errorCodeTypes from "./codeExamples/ErrorCodeTypes" -import generic from "../data/generic" -import multipleErrorCode from "./codeExamples/multipleErrorCode" -import multipleErrorCodeTs from "./codeExamples/multipleErrorCodeTs" -import TabGroup from "./TabGroup" -import typographyStyles from "../styles/typography.module.css" -import tableStyles from "../styles/table.module.css" - -function ApiErrors({ - api, - goToSection, -}: { - api: any - goToSection: (name: string, animate?: boolean) => void -}) { - return ( - <> - -

- errors:{" "} - {`Record`} -

-
- - {api.errors.description} - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{generic.name} - {generic.type} - {generic.description}
- type - - string - Error {generic.type}. eg: required, min, max, minLength
- types - - {`Record<{ string, string | boolean }>`} - {api.errors.types}
- message - - - string | React.ReactElement - - {api.errors.message}
- ref - - React.Ref - {api.errors.ref}
- {api.errors.note(goToSection)} -
- - - - - - -
- - ) -} - -export default memo(ApiErrors) diff --git a/src/components/ApiGallery.module.css b/src/components/ApiGallery.module.css index d7f929e00..e2f58bdfc 100644 --- a/src/components/ApiGallery.module.css +++ b/src/components/ApiGallery.module.css @@ -37,13 +37,14 @@ border: 1px solid var(--color-light-blue); position: relative; padding-bottom: 30px; - transition: 0.2s all; + transition: transform 0.3s ease; } .gallery li:hover { - transform: translate(-2px, -2px); - box-shadow: 2px 2px 0 4px black; border: 1px solid var(--color-secondary); + outline-width: 0; + box-shadow: 2px 2px 0 4px #000; + transform: translate(-2px,-2px); } .gallery li a { diff --git a/src/components/ApiGallery.tsx b/src/components/ApiGallery.tsx index c39228131..a3a1b9ca4 100644 --- a/src/components/ApiGallery.tsx +++ b/src/components/ApiGallery.tsx @@ -1,36 +1,20 @@ import { useEffect } from "react" -import { useStateMachine } from "little-state-machine" import Link from "next/link" import Footer from "./Footer" import typographyStyles from "../styles/typography.module.css" import styles from "./ApiGallery.module.css" import containerStyles from "../styles/container.module.css" import headerStyles from "./Header.module.css" -import { updateSetting } from "../actions/settingActions" import { useRouter } from "next/router" export default function ApiGallery() { - const { - actions, - state: { - setting = { - version: 7, - }, - }, - } = useStateMachine({ - updateSetting, - }) const router = useRouter() const onChange = (e) => { const version = parseInt(e.target.value) - actions.updateSetting({ - version, - }) - if (version !== 7) { - window.location.href = `https://legacy.react-hook-form.com/v${version}/api` + router.push(`https://legacy.react-hook-form.com/v${version}/api`) } else { router.push(`/v${version}/docs/`) } @@ -63,7 +47,7 @@ export default function ApiGallery() { ) { router.push(`/docs/${name}`) } - }, [setting, router]) + }, [router]) return (
diff --git a/src/components/ApiRefTable.tsx b/src/components/ApiRefTable.tsx index 6a382a7af..56c6fce88 100644 --- a/src/components/ApiRefTable.tsx +++ b/src/components/ApiRefTable.tsx @@ -138,7 +138,6 @@ export default function ApiRefTable({ api }: { api: any }) { `} /> @@ -160,7 +159,6 @@ export default function ApiRefTable({ api }: { api: any }) { {api.register.validation.required} {api.register.validation.maxLength} {api.register.validation.minLength} {api.register.validation.max} {api.register.validation.min} {api.register.validation.pattern} {api.register.validation.validate} console.log(e) @@ -606,7 +593,6 @@ export default function ApiRefTable({ api }: { api: any }) { console.log(e) @@ -630,7 +616,6 @@ export default function ApiRefTable({ api }: { api: any }) { @@ -655,7 +640,6 @@ export default function ApiRefTable({ api }: { api: any }) { - -

- watch:{" "} - {`(names?: string | string[] | (data, options) => void) => unknown`} -

-
- - {api.watch.description} - -

Props

- -
- - - - - - - - - - - - - - - - - - - - - - - -
- {generic.type} - - {generic.description} -
- string - {api.watch.tableTitle.single}
- string[] - {api.watch.tableTitle.multiple}
- undefined - {api.watch.tableTitle.all}
- {`(data: unknown, { name: string, type: string }) => void`} - {api.watch.tableTitle.callback}
-
- -

Return

- -
- - - - - - - - - - - - - - - - - - - - - - - -
- {generic.example} - - {generic.return} -
- watch('inputName') - - unknown -
- watch(['inputName1']) - - unknown[] -
- watch() - - {`{[key:string]: unknown}`} -
- {`watch((data, { name, type }) => console.log(data, name, type))`} - - {`{ unsubscribe: () => void }`} -
-
- -

- Rules -

- -
    -
  • -

    - When defaultValue is not defined, the first render of{" "} - watch will return undefined because it is - called before register. It's recommend to - provide defaultValues at useForm to avoid - this behaviour, but you can set the inline defaultValue{" "} - as the second argument. -

    -
  • -
  • -

    - When both defaultValue and defaultValues{" "} - are supplied, defaultValue will be returned. -

    -
  • -
  • -

    - This API will trigger re-render at the root of your app or form, - consider using a callback or the{" "} - useWatch api if you are - experiencing performance issues. -

    -
  • -
  • -

    - watch result is optimised for render phase instead of{" "} - useEffect's deps, to detect value update you may want - to use an external custom hook for value comparison. -

    -
  • -
- -

- Examples -

- - - - - - -

Video

- -

- The following video tutorial demonstrates watch API. -

- -