11import { ChevronDownIcon } from '@heroicons/react/24/outline' ;
22import * as Primitive from '@radix-ui/react-select' ;
3- import { useId } from 'react' ;
3+ import classNames from 'classnames' ;
4+ import Image from 'next/image' ;
5+ import { useId , useMemo } from 'react' ;
46import type { FC } from 'react' ;
57
68import styles from './index.module.css' ;
79
10+ type SelectValue = {
11+ label : string ;
12+ value : string ;
13+ iconImageUrl ?: string ;
14+ } ;
15+
816type SelectProps = {
9- values : ( { label : string ; value : string } | string ) [ ] ;
17+ values : SelectValue [ ] | string [ ] ;
1018 defaultValue ?: string ;
1119 placeholder ?: string ;
1220 dropdownLabel ?: string ;
1321 label ?: string ;
22+ inline ?: boolean ;
1423 onChange ?: ( value : string ) => void ;
1524} ;
1625
@@ -20,12 +29,23 @@ const Select: FC<SelectProps> = ({
2029 placeholder,
2130 label,
2231 dropdownLabel,
32+ inline,
2333 onChange,
2434} ) => {
2535 const id = useId ( ) ;
36+ const mappedValues = useMemo ( ( ) => {
37+ const [ firstItem ] = values ;
38+
39+ const items =
40+ typeof firstItem === 'string'
41+ ? values . map ( value => ( { value, label : value } ) )
42+ : values ;
43+
44+ return items as SelectValue [ ] ;
45+ } , [ values ] ) ;
2646
2747 return (
28- < div className = { styles . select } >
48+ < div className = { classNames ( styles . select , { [ styles . inline ] : inline } ) } >
2949 { label && (
3050 < label className = { styles . label } htmlFor = { id } >
3151 { label }
@@ -34,35 +54,43 @@ const Select: FC<SelectProps> = ({
3454 < Primitive . Root defaultValue = { defaultValue } onValueChange = { onChange } >
3555 < Primitive . Trigger
3656 className = { styles . trigger }
37- aria-label = { label }
57+ aria-label = { label || dropdownLabel }
3858 id = { id }
3959 >
4060 < Primitive . Value placeholder = { placeholder } />
4161 < ChevronDownIcon className = { styles . icon } />
4262 </ Primitive . Trigger >
4363 < Primitive . Portal >
44- < Primitive . Content className = { styles . dropdown } >
64+ < Primitive . Content
65+ position = { inline ? 'popper' : 'item-aligned' }
66+ className = { classNames ( styles . dropdown , { [ styles . inline ] : inline } ) }
67+ >
4568 < Primitive . Viewport >
4669 < Primitive . Group >
4770 { dropdownLabel && (
4871 < Primitive . Label className = { `${ styles . item } ${ styles . label } ` } >
4972 { dropdownLabel }
5073 </ Primitive . Label >
5174 ) }
52- { values . map ( item => {
53- const value = typeof item === 'string' ? item : item . value ;
54- const label = typeof item === 'string' ? item : item . label ;
55-
56- return (
57- < Primitive . Item
58- key = { value }
59- value = { value }
60- className = { `${ styles . item } ${ styles . text } ` }
61- >
62- < Primitive . ItemText > { label } </ Primitive . ItemText >
63- </ Primitive . Item >
64- ) ;
65- } ) }
75+ { mappedValues . map ( ( { value, label, iconImageUrl } ) => (
76+ < Primitive . Item
77+ key = { value }
78+ value = { value }
79+ className = { `${ styles . item } ${ styles . text } ` }
80+ >
81+ < Primitive . ItemText >
82+ { iconImageUrl && (
83+ < Image
84+ src = { iconImageUrl }
85+ alt = { label }
86+ width = { 16 }
87+ height = { 16 }
88+ />
89+ ) }
90+ { label }
91+ </ Primitive . ItemText >
92+ </ Primitive . Item >
93+ ) ) }
6694 </ Primitive . Group >
6795 </ Primitive . Viewport >
6896 </ Primitive . Content >
0 commit comments