44 useRef ,
55 ReactNode ,
66 SelectHTMLAttributes ,
7+ useMemo ,
78} from "react" ;
89
910import { DropdownDown , DropdownUp } from "@/assets/icon" ;
@@ -32,7 +33,6 @@ interface SelectProps
3233 placeholder ?: string ;
3334 size ?: keyof typeof sizeMap ;
3435 fullWidth ?: boolean ;
35- width ?: number | string ;
3636 className ?: string ;
3737 wrapperClassName ?: string ;
3838}
@@ -68,18 +68,19 @@ function Select({
6868 placeholder = "선택" ,
6969 size = "lg" ,
7070 fullWidth,
71- width,
7271 className,
7372 wrapperClassName,
7473 ...rest
7574} : SelectProps ) {
7675 const [ open , setOpen ] = useState ( false ) ;
7776 const [ buttonWidth , setButtonWidth ] = useState < number > ( 0 ) ;
7877
79- const wrapperRef = useRef < HTMLDivElement > ( null ) ;
78+ const wrapperRef = useRef < HTMLUListElement > ( null ) ;
8079 const buttonRef = useRef < HTMLButtonElement > ( null ) ;
8180
82- const selectedOption = options . find ( ( option ) => option . value === value ) ;
81+ const selectedOption = useMemo ( ( ) => {
82+ return options . find ( ( option ) => option . value === value ) ;
83+ } , [ options , value ] ) ;
8384
8485 const wrapperClassNames = cn (
8586 "relative" ,
@@ -90,18 +91,19 @@ function Select({
9091 ) ;
9192
9293 const buttonClassNames = cn (
93- "flex items-center justify-between rounded-[0.375rem]" ,
94+ "flex items-center justify-between rounded-[0.375rem] cursor-pointer " ,
9495 {
9596 "w-full" : fullWidth ,
96- "bg-white placeholder:text-gray-40 border border-gray-30" : size === "lg" ,
97+ "bg-white border border-gray-30" : size === "lg" ,
9798 "bg-gray-10 font-bold" : size === "sm" ,
9899 } ,
100+ value ? "text-black" : "text-gray-40" ,
99101 sizeMap [ size ] ,
100102 className ,
101103 ) ;
102104
103105 const listClassNames = cn (
104- "absolute top-full left-0 mt-1 border rounded-[0.375rem] bg-white border-gray-30 shadow-lg z-10 max-h-48 overflow-y-auto" ,
106+ "absolute top-full left-0 mt-1 border rounded-[0.375rem] bg-white border-gray-30 text-black shadow-lg z-10 max-h-48 overflow-y-auto" ,
105107 ) ;
106108
107109 const handleSelect = ( selectedValue : string ) => {
@@ -112,9 +114,10 @@ function Select({
112114 // 드롭다운 외부 클릭 시 닫기
113115 useEffect ( ( ) => {
114116 const handleClickOutside = ( event : MouseEvent ) => {
117+ const target = event . target as Node ;
115118 if (
116- wrapperRef . current &&
117- ! wrapperRef . current . contains ( event . target as Node )
119+ ! buttonRef . current ?. contains ( target ) &&
120+ ! wrapperRef . current ? .contains ( target )
118121 ) {
119122 setOpen ( false ) ;
120123 }
@@ -136,19 +139,16 @@ function Select({
136139
137140 return (
138141 < Field id = { id } label = { label } >
139- < div className = { wrapperClassNames } ref = { wrapperRef } >
142+ < div className = { wrapperClassNames } >
140143 < button
141144 id = { id }
142145 type = "button"
143146 ref = { buttonRef }
144147 onClick = { ( ) => setOpen ( ( prev ) => ! prev ) }
145148 className = { buttonClassNames }
146- style = { width ? { width } : undefined }
147149 { ...rest }
148150 >
149- < span className = { cn ( value ? "" : "text-gray-40" ) } >
150- { selectedOption ?. label || placeholder }
151- </ span >
151+ { selectedOption ?. label || placeholder }
152152 { open ? (
153153 < DropdownUp className = "ml-2" />
154154 ) : (
@@ -158,9 +158,10 @@ function Select({
158158
159159 { open && (
160160 < ul
161+ ref = { wrapperRef }
161162 className = { listClassNames }
162163 style = { {
163- width : width || buttonWidth ,
164+ width : buttonWidth ,
164165 } }
165166 >
166167 { options . map ( ( option ) => (
@@ -171,7 +172,7 @@ function Select({
171172 < button
172173 type = "button"
173174 className = { cn (
174- "w-full text-center hover:bg-gray-10" ,
175+ "w-full text-center hover:bg-gray-10 cursor-pointer " ,
175176 size === "sm"
176177 ? "px-3 py-2 text-sm"
177178 : "px-5 py-3 text-[1rem]" ,
0 commit comments