"use client"; /* eslint-disable react/prop-types */ import * as React from "react"; import { Controller, FormProvider, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch, type Control, type ControllerFieldState, type ControllerProps, type ControllerRenderProps, type DefaultValues, type FieldError, type FieldErrors, type FieldPath, type FieldValues, type Path, type RegisterOptions, type Resolver, type SubmitHandler, type UseControllerReturn, type UseFieldArrayReturn, type UseFormReturn, } from "react-hook-form"; import {cn} from "@/lib/utilities"; import styles from "./form.module.css"; /** * Provides the `react-hook-form` context to nested form primitives. * * @remarks * - Renders the `FormProvider` component from `react-hook-form` * - Built on `react-hook-form` * * @example * ```tsx *
* ...
* * ``` * * @see {@link https://react-hook-form.com/docs/formprovider | React Hook Form FormProvider Docs} */ const Form = Object.assign(FormProvider, {displayName: "Form"}); type FormControlElementProps = React.HTMLAttributes & { ref?: React.Ref; }; interface FormControlProps extends Omit, "children"> { /** * Single form control element or fallback content to receive field accessibility attributes. * @default undefined */ children: React.ReactNode; } function assignRef(ref: React.Ref | undefined, value: TValue | null): void { if (typeof ref === "function") { ref(value); return; } if (ref) { ref.current = value; } } function composeRefs(...refs: Array | undefined>): React.RefCallback { return (value: TValue | null): void => { for (const ref of refs) { assignRef(ref, value); } }; } function mergeAriaDescribedBy(...describedByValues: Array): string | undefined { const tokens = describedByValues .flatMap((describedByValue) => describedByValue?.split(/\s+/u) ?? []) .filter((token): token is string => token.length > 0); return tokens.length > 0 ? [...new Set(tokens)].join(" ") : undefined; } type FormFieldContextValue< TFieldValues extends FieldValues = FieldValues, TName extends FieldPath = FieldPath, > = { name: TName; }; const FormFieldContext = React.createContext(null); /** * Binds a single field name to the shared form field context. * * @remarks * - Renders the `Controller` component from `react-hook-form` * - Built on `react-hook-form` controller primitives * * @example * ```tsx * } * /> * ``` * * @see {@link https://react-hook-form.com/docs/usecontroller/controller | React Hook Form Controller Docs} */ const FormField = = FieldPath>({ ...props }: ControllerProps): React.JSX.Element => { return ( ); }; type UseFormFieldReturn = { id: string; name: FieldPath; formItemId: string; formDescriptionId: string; formMessageId: string; invalid: boolean; isDirty: boolean; isTouched: boolean; isValidating: boolean; error?: ReturnType["getFieldState"]>["error"]; }; /** * Returns the resolved form field metadata for nested form primitives. * * @remarks * Reads the nearest {@link FormField} and {@link FormItem} contexts, then combines them * with `react-hook-form` field state to expose stable IDs and validation metadata. * * @example * ```tsx * const field = useFormField(); * ``` * * @see {@link https://react-hook-form.com/docs/useformcontext | React Hook Form useFormContext Docs} */ const useFormField = (): UseFormFieldReturn => { const fieldContext = React.useContext(FormFieldContext); const itemContext = React.useContext(FormItemContext); const {getFieldState, formState} = useFormContext(); if (!fieldContext) { throw new Error("useFormField should be used within "); } if (!itemContext) { throw new Error("useFormField should be used within "); } const fieldState = getFieldState(fieldContext.name, formState); const {id} = itemContext; return { error: fieldState.error, formDescriptionId: `${id}-form-item-description`, formItemId: `${id}-form-item`, formMessageId: `${id}-form-item-message`, id, invalid: fieldState.invalid, isDirty: fieldState.isDirty, isTouched: fieldState.isTouched, isValidating: fieldState.isValidating, name: fieldContext.name as FieldPath, }; }; type FormItemContextValue = { id: string; }; const FormItemContext = React.createContext(null); /** * Wraps a label, control, description, and message into a single form item. * * @remarks * - Renders a `
` element * - Built on the shared form item context * * @example * ```tsx * * Email * * ``` * * @see {@link https://react-hook-form.com/docs/useformcontext | React Hook Form Docs} */ const FormItem = React.forwardRef>(({className, ...props}, ref) => { const id = React.useId(); return (
); }); FormItem.displayName = "FormItem"; /** * Renders the accessible label for the current form item. * * @remarks * - Renders a `