diff --git a/contentlayer.config.ts b/contentlayer.config.ts index bcd47dd5d..113cbfcca 100644 --- a/contentlayer.config.ts +++ b/contentlayer.config.ts @@ -4,6 +4,7 @@ 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" +import { rehypeHeadingAnchors } from "./src/components/logic/rehypeHeadingAnchors" import type { Pages } from "./src/types/types" export const Doc = defineDocumentType(() => ({ @@ -61,6 +62,6 @@ export default makeSource({ documentTypes: [Doc], mdx: { remarkPlugins: [remarkGfm, remarkHeadingId, emoji], - rehypePlugins: [rehypeMdxCodeProps], + rehypePlugins: [rehypeMdxCodeProps, rehypeHeadingAnchors], }, }) diff --git a/package.json b/package.json index 0dafad095..b0152dd36 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "6.0.1", "author": "beier luo", "dependencies": { - "@hookform/devtools": "4.3.1", + "@hookform/devtools": "4.4.0", "@mdx-js/loader": "^2.3.0", "@mdx-js/react": "^2.3.0", "@next/mdx": "15.1.0", @@ -20,8 +20,7 @@ "react": "18.3.1", "react-dom": "18.3.1", "react-flip-numbers": "^3.0.9", - "react-github-btn": "1.4.0", - "react-hook-form": "7.44.3", + "react-hook-form": "8.0.0-beta.4", "react-simple-animate": "^3.5.3", "react-simple-img": "3.0.0", "react-sortablejs": "1.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7e968dbe0..0c2dcaa81 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,8 +13,8 @@ importers: .: dependencies: '@hookform/devtools': - specifier: 4.3.1 - version: 4.3.1(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 4.4.0 + version: 4.4.0(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mdx-js/loader': specifier: ^2.3.0 version: 2.3.0(webpack@5.95.0(esbuild@0.24.0)) @@ -60,12 +60,9 @@ importers: react-flip-numbers: specifier: ^3.0.9 version: 3.0.9(react-dom@18.3.1(react@18.3.1))(react-simple-animate@3.5.3(react-dom@18.3.1(react@18.3.1)))(react@18.3.1) - react-github-btn: - specifier: 1.4.0 - version: 1.4.0(react@18.3.1) react-hook-form: - specifier: 7.44.3 - version: 7.44.3(react@18.3.1) + specifier: 8.0.0-beta.4 + version: 8.0.0-beta.4(@types/react@18.3.17)(react@18.3.1) react-simple-animate: specifier: ^3.5.3 version: 3.5.3(react-dom@18.3.1(react@18.3.1)) @@ -522,11 +519,11 @@ packages: engines: {node: '>=6'} hasBin: true - '@hookform/devtools@4.3.1': - resolution: {integrity: sha512-CrWxEoHQZaOXJZVQ8KBgOuAa8p2LI8M0DAN5GTRTmdCieRwFVjVDEmuTAVazWVRRkpEQSgSt3KYp7VmmqXdEnw==} + '@hookform/devtools@4.4.0': + resolution: {integrity: sha512-Mtlic+uigoYBPXlfvPBfiYYUZuyMrD3pTjDpVIhL6eCZTvQkHsKBSKeZCvXWUZr8fqrkzDg27N+ZuazLKq6Vmg==} peerDependencies: - react: ^16.8.0 || ^17 || ^18 - react-dom: ^16.8.0 || ^17 || ^18 + react: ^16.8.0 || ^17 || ^18 || ^19 + react-dom: ^16.8.0 || ^17 || ^18 || ^19 '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} @@ -700,15 +697,9 @@ packages: '@jridgewell/source-map@0.3.11': resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/sourcemap-codec@1.6.0': resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} - '@jridgewell/trace-mapping@0.3.30': - resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} - '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} @@ -2083,9 +2074,6 @@ packages: get-tsconfig@4.10.1: resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} - github-buttons@2.29.1: - resolution: {integrity: sha512-TV3YgAKda5hPz75n7QXmGCsSzgVya1vvmBieebg3EB5ScmashTZ0FldViG1aU2d4V5rcAGrtQ7k5uAaCo0A4PA==} - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3025,16 +3013,15 @@ packages: react-dom: ^16.8.0 || ^17 || ^18 || ^19 react-simple-animate: ^3.0.1 - react-github-btn@1.4.0: - resolution: {integrity: sha512-lV4FYClAfjWnBfv0iNlJUGhamDgIq6TayD0kPZED6VzHWdpcHmPfsYOZ/CFwLfPv4Zp+F4m8QKTj0oy2HjiGXg==} - peerDependencies: - react: '>=16.3.0' - - react-hook-form@7.44.3: - resolution: {integrity: sha512-/tHId6p2ViAka1wECMw8FEPn/oz/w226zehHrJyQ1oIzCBNMIJCaj6ZkQcv+MjDxYh9MWR7RQic7Qqwe4a5nkw==} - engines: {node: '>=12.22.0'} + react-hook-form@8.0.0-beta.4: + resolution: {integrity: sha512-kTdfgnDwiBFBRLqp7fIbxhIMHTco5H0QN5IJ6zYrtFqx8NQds8GZwXlStIsqK+L4TeAu0oQI7XhE0nO1pSwoKQ==} + engines: {node: '>=18.0.0'} peerDependencies: - react: ^16.8.0 || ^17 || ^18 + '@types/react': 18.3.17 + react: ^16.8.0 || ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -3702,7 +3689,7 @@ snapshots: '@babel/parser': 7.28.4 '@babel/types': 7.28.4 '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-globals@7.28.0': {} @@ -4114,7 +4101,7 @@ snapshots: protobufjs: 7.5.4 yargs: 17.7.2 - '@hookform/devtools@4.3.1(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@hookform/devtools@4.4.0(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@emotion/react': 11.14.0(@types/react@18.3.17)(react@18.3.1) '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.17)(react@18.3.1))(@types/react@18.3.17)(react@18.3.1) @@ -4250,8 +4237,8 @@ snapshots: '@jridgewell/gen-mapping@0.3.13': dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/resolve-uri@3.1.2': {} @@ -4260,15 +4247,8 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/sourcemap-codec@1.6.0': {} - '@jridgewell/trace-mapping@0.3.30': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -5889,8 +5869,6 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - github-buttons@2.29.1: {} - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -7124,14 +7102,11 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-simple-animate: 3.5.3(react-dom@18.3.1(react@18.3.1)) - react-github-btn@1.4.0(react@18.3.1): - dependencies: - github-buttons: 2.29.1 - react: 18.3.1 - - react-hook-form@7.44.3(react@18.3.1): + react-hook-form@8.0.0-beta.4(@types/react@18.3.17)(react@18.3.1): dependencies: react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.17 react-is@16.13.1: {} diff --git a/src/components/ApiGallery.module.css b/src/components/ApiGallery.module.css deleted file mode 100644 index 50a68214c..000000000 --- a/src/components/ApiGallery.module.css +++ /dev/null @@ -1,107 +0,0 @@ -.root { - max-width: 768px; - margin: var(--space-12) auto 0; -} - -@media (min-width: 768px) { - .root { - max-width: 840px; - } -} - -.gallery { - display: grid; - list-style: none; - margin: var(--space-5); - grid-gap: 25px; - grid-template-columns: 1fr; - padding: 0; -} - -@media (min-width: 768px) { - .gallery { - margin: var(--space-12) auto; - padding: 0 var(--space-5); - grid-gap: 25px; - grid-template-columns: repeat(3, 1fr); - } -} - -@media (min-width: 1024px) { - .gallery { - max-width: 1024px; - } -} - -.gallery li { - border: 1px solid var(--color-border); - position: relative; - padding-bottom: var(--space-7); - transition: transform var(--transition); - border-radius: var(--radius-md); - overflow: hidden; -} - -.gallery li:hover { - border: 1px solid var(--color-secondary); - outline-width: 0; - box-shadow: 2px 2px 0 4px #000; - transform: translate(-2px, -2px); -} - -.gallery li a { - position: absolute; - right: 0; - bottom: 0; - top: 0; - left: 0; - display: flex; - justify-content: flex-end; - align-items: flex-end; - padding: var(--space-3) var(--space-5) var(--space-3) var(--space-16); - font-size: var(--text-sm); -} - -.gallery h3 { - color: var(--color-text); - margin: 0; - font-weight: normal; - padding: var(--space-3) var(--space-5); - font-size: 18px; - background: var(--color-surface); - border-bottom: 1px solid var(--color-border); - letter-spacing: 1px; -} - -.gallery h3 code { - margin-right: var(--space-1); - letter-spacing: -1px; - color: var(--color-light-pink); -} - -.gallery p { - margin: var(--space-5); - font-size: var(--text-sm); -} - -.versionControl { - text-align: right; - padding-right: var(--space-5); -} - -.versionControl > div { - display: inline-block; -} - -.versionControl > p { - font-size: var(--text-sm); - color: var(--color-light-grey); - display: inline-block; - margin-right: var(--space-5); -} - -p.beta { - margin-bottom: -1rem; - font-size: var(--text-xs); - color: var(--color-light-grey); -} diff --git a/src/components/ApiGallery.tsx b/src/components/ApiGallery.tsx index a7dd70fa2..9c54629e8 100644 --- a/src/components/ApiGallery.tsx +++ b/src/components/ApiGallery.tsx @@ -1,236 +1,119 @@ import { useEffect } from "react" -import type { MouseEventHandler } from "react" 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 clsx from "clsx" import { useRouter } from "next/router" +import Footer from "./Footer" +import { apiLinks } from "./Menu/MenuLinks" +import PageHeader from "./PageHeader" +import cards from "../styles/cards.module.css" -export default function ApiGallery() { - const router = useRouter() +const DESCRIPTIONS: Record = { + "/docs/useform": + "A powerful custom hook to validate your form with minimal re-renders.", + "/docs/usecontroller": + "For controlled components: interface with the useForm methods and isolate its re-render.", + "/docs/useformcontext": + "Access your useForm methods and properties from nested components. Great for building larger forms and shared components.", + "/docs/usewatch": + "Subscribe to individual form input changes without impacting the root component's render.", + "/docs/useformstate": + "Subscribe to individual form state updates and isolate re-renders at the hook level.", + "/docs/usefieldarray": + "Manage dynamically generated fields on the fly: shuffle, remove and append fields. Ideal for complex CRUD data entry.", + "/docs/uselens": + "Type-safe lenses for building reusable and shareable form components with precise focus on form fields.", + "/docs/createFormControl": + "Create a form control object and subscribe to form state outside of React components, accessing methods without context.", +} - const onChange: MouseEventHandler = (e) => { - const version = parseInt( - (e.target as HTMLElement).getAttribute("value") as string - ) +const MAX_CHILDREN = 8 - if (version !== 7) { - router.push( - `https://react-hook-form-website-git-leagcy-hook-form.vercel.app/v${version}/api` - ) - } else { - router.push(`/v${version}/docs/`) - } - } +// Old /docs#name links from the v6 era redirect to the matching page. +const USEFORM_HASHES = [ + "register", + "unregister", + "watch", + "handlesubmit", + "reset", + "seterror", + "clearerrors", + "setvalues", + "getvalues", + "trigger", + "control", + "formstate", +] + +export default function ApiGallery() { + const router = useRouter() useEffect(() => { const name = window.location.hash.toLowerCase().slice(1) if (name === "controller") { router.push(`/docs/usecontroller/${name}`) - } else if ( - [ - "register", - "unregister", - "watch", - "handlesubmit", - "reset", - "setError", - "clearerrors", - "setvalues", - "getvalues", - "trigger", - "control", - "formstate", - ].includes(name) - ) { + } else if (USEFORM_HASHES.includes(name)) { router.push(`/docs/useform/${name}`) - } else if ( - ["controller", "useformcontext", "usefieldarray"].includes(name) - ) { + } else if (["useformcontext", "usefieldarray"].includes(name)) { router.push(`/docs/${name}`) } }, [router]) return ( -
-

- API -

-

- React Hook Form's API overview -

+
+ -
-
    -
  • -
    -

    - {``}useForm -

    -

    - A powerful custom hook to validate your form with minimal - re-renders. -

    - - Read More ▸ - -
    -
  • -
  • -
    -

    - {``}useController -

    -

    - For Controlled components: interface with the useForm methods - and isolate its re-render. -

    - - Read More ▸ - -
    -
  • -
  • -
    -

    - {``}useFormContext -

    -

    - Access your useForm methods and properties from nested - components. Great for building larger forms and shared - components! -

    - - Read More ▸ - -
    -
  • -
  • -
    -

    - {``}useWatch -

    -

    - Subscribe to individual form input changes without impacting the - root component's render. -

    - - Read More ▸ - -
    -
  • -
  • -
    -

    - {``}useFormState -

    -

    - Subscribe to individual form state updates and isolating - re-renders at the hook level. -

    - - Read More ▸ - -
    -
  • -
  • -
    -

    - {``}useFieldArray -

    -

    - Manage dynamically generated fields on the fly, shuffle, remove - and append fields. Ideal for complex CRUD data entry scenarios. -

    - - Read More ▸ - -
    -
  • -
  • -
    -

    - {``}useLens -

    -

    - Type-safe lenses for building reusable and shareable form - components with precise focus on form fields. -

    - - Read More ▸ - -
    -
  • -
  • -
    -

    - {``}createFormControl -

    -

    - Create form control object and subscribe form state outside of - React component, access methods without context. -

    - - Read More ▸ - -
    -
  • -
+
+
    + {apiLinks.map((api) => { + const children = api.pages ?? [] + const hidden = children.length - MAX_CHILDREN + + return ( +
  • + + + {``} + +

    {api.name}

    +

    {DESCRIPTIONS[api.pathname]}

    + + Read more → + + -
    -

    Switch Version:

    -
    - - - -
    -
    + {children.length > 0 && ( +
      + {children.slice(0, MAX_CHILDREN).map((child) => ( +
    • + + {child.name} + +
    • + ))} + {hidden > 0 && ( +
    • + + +{hidden} more + +
    • + )} +
    + )} +
  • + ) + })} +