From 3ef27958441246afa8c2ec06aaffabacc26be13d Mon Sep 17 00:00:00 2001 From: leedj312 Date: Wed, 5 Mar 2025 13:08:33 +0900 Subject: [PATCH] =?UTF-8?q?form=20=20component=20=EC=B4=88=EA=B8=B0=20?= =?UTF-8?q?=EC=9E=91=EC=97=85=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business_components/src/ui/form/form.tsx | 174 +++++++++++++++ .../business_components/src/ui/form/index.tsx | 198 ++++-------------- .../business_components/src/ui/form/test.tsx | 56 +++++ 3 files changed, 265 insertions(+), 163 deletions(-) create mode 100644 packages/common/business_components/src/ui/form/form.tsx create mode 100644 packages/common/business_components/src/ui/form/test.tsx diff --git a/packages/common/business_components/src/ui/form/form.tsx b/packages/common/business_components/src/ui/form/form.tsx new file mode 100644 index 000000000..cc63a6e7d --- /dev/null +++ b/packages/common/business_components/src/ui/form/form.tsx @@ -0,0 +1,174 @@ +"use client" + +import * as LabelPrimitive from "@radix-ui/react-label" +import { Slot } from "@radix-ui/react-slot" +import * as React from "react" +import { + Controller, + type ControllerProps, + type FieldPath, + type FieldValues, + FormProvider, + useFormContext, +} from "react-hook-form" + +import { cn } from "../../lib/utils" +import { Label } from "./label" + +const Form = FormProvider + +type FormFieldContextValue< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +> = { + name: TName +} + +const FormFieldContext = React.createContext( + {} as FormFieldContextValue +) + +const FormField = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +>({ + ...props +}: ControllerProps) => { + return ( + + + + ) +} + +const useFormField = () => { + const fieldContext = React.useContext(FormFieldContext) + const itemContext = React.useContext(FormItemContext) + const { getFieldState, formState } = useFormContext() + + const fieldState = getFieldState(fieldContext.name, formState) + + if (!fieldContext) { + throw new Error("useFormField should be used within ") + } + + const { id } = itemContext + + return { + id, + name: fieldContext.name, + formItemId: `${id}-form-item`, + formDescriptionId: `${id}-form-item-description`, + formMessageId: `${id}-form-item-message`, + ...fieldState, + } +} + +type FormItemContextValue = { + id: string +} + +const FormItemContext = React.createContext( + {} as FormItemContextValue +) + +const FormItem = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => { + const id = React.useId() + + return ( + +
+ + ) +}) +FormItem.displayName = "FormItem" + +const FormLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + const { error, formItemId } = useFormField() + + return ( +