@@ -11,7 +11,6 @@ import {
1111
1212import { Label } from "@codevs/ui/label" ;
1313
14- // Extend your interface to include a "searchable" prop.
1514interface Option {
1615 id : string ;
1716 value : string ;
@@ -21,14 +20,14 @@ interface Option {
2120}
2221
2322interface CustomSelectProps {
24- label : string ;
23+ label ? : string ; // ← made optional: omit to suppress the heading entirely
2524 options : Option [ ] ;
2625 value ?: string ;
2726 onChange : ( value : string ) => void ;
2827 placeholder ?: string ;
2928 disabled ?: boolean ;
3029 variant ?: "default" | "simple" ;
31- searchable ?: boolean ; // <--- New prop
30+ searchable ?: boolean ;
3231}
3332
3433export const CustomSelect = ( {
@@ -38,14 +37,12 @@ export const CustomSelect = ({
3837 onChange,
3938 placeholder,
4039 disabled,
41- variant = "default" , // Default to showing avatars
42- searchable = false , // <--- Default false
40+ variant = "default" ,
41+ searchable = false ,
4342} : CustomSelectProps ) => {
44- // Keep track of the user's search term
4543 const [ searchTerm , setSearchTerm ] = useState ( "" ) ;
4644 const searchInputRef = useRef < HTMLInputElement > ( null ) ;
4745
48- // Filter options based on the search term
4946 const filteredOptions = useMemo ( ( ) => {
5047 if ( ! searchable ) return options ;
5148 const lowerSearch = searchTerm . toLowerCase ( ) ;
@@ -57,23 +54,24 @@ export const CustomSelect = ({
5754 } ) ;
5855 } , [ options , searchable , searchTerm ] ) ;
5956
60- // Handle user typing in the search input
6157 const handleSearchChange = ( e : ChangeEvent < HTMLInputElement > ) => {
62- // Stop event propagation so the dropdown doesn't close
6358 e . stopPropagation ( ) ;
6459 setSearchTerm ( e . target . value ) ;
6560 } ;
6661
6762 return (
6863 < div className = "space-y-2" >
69- < Label className = "dark:text-light-900 text-black" > { label } </ Label >
64+ { /* Render label only when provided — prevents duplicate headings when
65+ the parent component already renders its own label above this select. */ }
66+ { label && (
67+ < Label className = "dark:text-light-900 text-black" > { label } </ Label >
68+ ) }
7069 < Select value = { value } onValueChange = { onChange } disabled = { disabled } >
7170 < SelectTrigger className = "bg-light-800 dark:bg-dark-200 border-light-700 dark:border-dark-200 dark:text-light-900 w-full text-black" >
7271 < SelectValue placeholder = { disabled ? "Loading..." : placeholder } />
7372 </ SelectTrigger >
7473
7574 < SelectContent side = "bottom" position = "popper" sideOffset = { 4 } className = "bg-light-800 dark:bg-dark-200" >
76- { /** If searchable, show an inline search input */ }
7775 { searchable && (
7876 < div className = "p-2" >
7977 < input
@@ -82,10 +80,10 @@ export const CustomSelect = ({
8280 placeholder = "Search..."
8381 value = { searchTerm }
8482 onChange = { handleSearchChange }
85- onPointerDown = { ( e ) => e . stopPropagation ( ) } // Keep dropdown open
86- onFocus = { ( e ) => e . stopPropagation ( ) } // Keep dropdown open
83+ onPointerDown = { ( e ) => e . stopPropagation ( ) }
84+ onFocus = { ( e ) => e . stopPropagation ( ) }
8785 onKeyDown = { ( e ) => {
88- e . stopPropagation ( ) ; // Prevent Select keyboard navigation
86+ e . stopPropagation ( ) ;
8987 } }
9088 autoFocus = { false }
9189 className = "dark:bg-dark-100 w-full rounded-md bg-white p-2 text-sm dark:text-white"
@@ -126,7 +124,6 @@ export const CustomSelect = ({
126124 </ div >
127125 </ div >
128126 ) : (
129- // Simple variant without avatar
130127 < div className = "flex flex-col" >
131128 < span > { option . label } </ span >
132129 { option . subLabel && (
@@ -144,4 +141,4 @@ export const CustomSelect = ({
144141 </ Select >
145142 </ div >
146143 ) ;
147- } ;
144+ } ;
0 commit comments