1- import { type ComponentProps , useId } from "react" ;
1+ import { type ElementType , type ReactNode , useId } from "react" ;
2+
3+ import { type PolymorphicComponentPropsWithRef } from "@/types/polymorphic.types" ;
24
35import * as styles from "./TextField.css" ;
46
57type Status = "inactive" | "negative" ;
68
7- export type TextFieldProps = {
8- label ?: string ;
9- helperText ?: string ;
10- status ?: Status ;
11- rightAddon ?: React . ReactNode ;
12- } & ComponentProps < "input" > ;
9+ export type TextFieldProps < T extends ElementType > =
10+ PolymorphicComponentPropsWithRef <
11+ T ,
12+ {
13+ label ?: string | ReactNode ;
14+ helperText ?: string ;
15+ status ?: Status ;
16+ rightAddon ?: ReactNode ;
17+ }
18+ > ;
1319
14- export const TextField = ( {
20+ /**
21+ * TextField 컴포넌트
22+ * @description 기본은 input이지만, as="textarea"처럼 다른 태그로도 변경 가능
23+ * @example
24+ * ```tsx
25+ * <TextField placeholder="기본 input" />
26+ * <TextField as="textarea" placeholder="textarea로 사용" rows={4} />
27+ * ```
28+ */
29+ export const TextField = < T extends ElementType = "input" > ( {
30+ as,
31+ className,
1532 label,
1633 helperText,
1734 status = "inactive" ,
1835 rightAddon,
36+ ref,
1937 ...props
20- } : TextFieldProps ) => {
38+ } : TextFieldProps < T > ) => {
39+ const Component = as || "input" ;
2140 const inputId = useId ( ) ;
2241 const helperId = `${ inputId } -helper` ;
2342
@@ -30,10 +49,11 @@ export const TextField = ({
3049 ) }
3150
3251 < div className = { styles . inputWrapper } >
33- < input
52+ < Component
3453 id = { inputId }
35- className = { styles . input ( { status } ) }
36- aria-label = { label }
54+ ref = { ref }
55+ className = { `${ styles . input ( { status } ) } ${ className ?? "" } ` }
56+ aria-label = { typeof label === "string" ? label : undefined }
3757 aria-describedby = { helperText ? helperId : undefined }
3858 { ...props }
3959 />
0 commit comments