11import MuiAutocomplete from '@mui/material/Autocomplete'
22import React , { JSX , useState } from 'react'
3- import ArrowDropDownIcon from '@mui/icons-material/ExpandMore'
43
5- import type {
6- AutocompleteChangeDetails ,
7- AutocompleteChangeReason ,
8- AutocompleteProps ,
9- AutocompleteRenderInputParams ,
10- } from '@mui/material/Autocomplete'
4+ import type { AutocompleteProps , AutocompleteRenderInputParams } from '@mui/material/Autocomplete'
5+ import ArrowDropDownIcon from '@mui/icons-material/ExpandMore'
116import { TextField } from './TextField'
7+
128import type { TextFieldProps } from './TextField'
139
1410export interface EnhancedAutocompleteProps <
15- T ,
11+ T extends { label : string } ,
1612 Multiple extends boolean | undefined = undefined ,
1713 DisableClearable extends boolean | undefined = undefined ,
1814 FreeSolo extends boolean | undefined = undefined ,
@@ -23,8 +19,6 @@ export interface EnhancedAutocompleteProps<
2319 helperText ?: TextFieldProps [ 'helperText' ]
2420 /** A required label for the Autocomplete to ensure accessibility. */
2521 label : string
26- /** Optional field to hide label, mostly used in Key value components */
27- hideLabel ?: boolean
2822 /** Removes the top margin from the input label, if desired. */
2923 noMarginTop ?: boolean
3024 /** Element to show when the Autocomplete search yields no results. */
@@ -33,105 +27,76 @@ export interface EnhancedAutocompleteProps<
3327 renderInput ?: ( _params : AutocompleteRenderInputParams ) => React . ReactNode
3428 /** Label for the "select all" option. */
3529 selectAllLabel ?: string
36- /** Removes the "select all" option for multiselect */
37- disableSelectAll ?: boolean
3830 textFieldProps ?: Partial < TextFieldProps >
3931 width ?: 'small' | 'medium' | 'large'
4032}
4133
34+ /**
35+ * An Autocomplete component that provides a user-friendly select input
36+ * allowing selection between options.
37+ *
38+ * @example
39+ * <Autocomplete
40+ * label="Select a Fruit"
41+ * onSelectionChange={(selected) => console.log(selected)}
42+ * options={[
43+ * {
44+ * label: 'Apple',
45+ * value: 'apple',
46+ * }
47+ * ]}
48+ * />
49+ */
4250export function Autocomplete <
43- T ,
51+ T extends { label : string } ,
4452 Multiple extends boolean | undefined = undefined ,
4553 DisableClearable extends boolean | undefined = undefined ,
4654 FreeSolo extends boolean | undefined = undefined ,
4755> ( props : EnhancedAutocompleteProps < T , Multiple , DisableClearable , FreeSolo > ) {
4856 const {
4957 clearOnBlur,
5058 defaultValue,
51- disablePortal = false ,
59+ disablePortal = true ,
5260 errorText = '' ,
5361 helperText,
54- hideLabel = false ,
5562 label,
5663 limitTags = 2 ,
5764 loading = false ,
5865 loadingText,
59- multiple,
60- disableSelectAll = false ,
6166 noOptionsText,
6267 onBlur,
6368 options,
6469 placeholder,
6570 renderInput,
66- selectAllLabel = '' ,
6771 textFieldProps,
6872 value,
6973 onChange,
7074 width = 'medium' ,
7175 ...rest
7276 } = props
73-
7477 const [ inPlaceholder , setInPlaceholder ] = useState ( '' )
7578
76- // --- select-all logic ---
77- const isSelectAllActive = multiple && Array . isArray ( value ) && value . length === options . length
78-
79- const selectAllText = isSelectAllActive ? 'Deselect All' : 'Select All'
80- const selectAllOption = { label : `${ selectAllText } ${ selectAllLabel } ` } as unknown as T
81- const optionsWithSelectAll = [ selectAllOption , ...options ]
82-
83- const handleChange : AutocompleteProps < T , Multiple , DisableClearable , FreeSolo > [ 'onChange' ] = (
84- e ,
85- newValue ,
86- reason : AutocompleteChangeReason ,
87- details ?: AutocompleteChangeDetails < T > ,
88- ) => {
89- if ( ! onChange ) return
90-
91- // if they clicked the "Select All" option
92- if ( details ?. option === selectAllOption ) {
93- const next = isSelectAllActive ? ( [ ] as unknown as typeof newValue ) : ( options as unknown as typeof newValue )
94- onChange ( e , next , reason , details )
95- } else onChange ( e , newValue , reason , details )
96- }
97- // --------------------------
98-
9979 return (
10080 < MuiAutocomplete
101- options = { multiple && ! disableSelectAll && options . length > 0 ? optionsWithSelectAll : options }
102- multiple = { multiple }
103- disableCloseOnSelect = { multiple }
104- clearOnBlur = { clearOnBlur }
105- data-qa-autocomplete = { label }
106- defaultValue = { defaultValue }
107- disablePortal = { disablePortal }
108- limitTags = { limitTags }
109- loading = { loading }
110- loadingText = { loadingText || 'Loading...' }
111- noOptionsText = { noOptionsText || < i > You have no options to choose from</ i > }
112- onBlur = { onBlur }
113- onOpen = { ( ) => setInPlaceholder ( 'Search' ) }
114- onClose = { ( ) => setInPlaceholder ( placeholder || '' ) }
115- popupIcon = { < ArrowDropDownIcon /> }
81+ options = { options }
11682 renderInput = {
11783 renderInput ||
11884 ( ( params ) => (
11985 < TextField
120- hideLabel = { hideLabel }
12186 label = { label }
12287 width = { width }
12388 loading = { loading }
124- placeholder = { inPlaceholder || placeholder || 'Select an option' }
89+ placeholder = { inPlaceholder || ( placeholder ?? 'Select an option' ) }
12590 { ...params }
12691 error = { ! ! errorText }
12792 helperText = { helperText }
12893 InputProps = { {
12994 ...params . InputProps ,
13095 ...textFieldProps ?. InputProps ,
13196 sx : {
132- display : 'flex ' ,
133- flexWrap : 'wrap ' ,
134- gap : 1 ,
97+ overflow : 'hidden ' ,
98+ whiteSpace : 'nowrap ' ,
99+ textOverflow : 'ellipsis' ,
135100 paddingRight : '44px' ,
136101 } ,
137102 } }
@@ -141,9 +106,21 @@ export function Autocomplete<
141106 />
142107 ) )
143108 }
109+ clearOnBlur = { clearOnBlur }
110+ data-qa-autocomplete = { label }
111+ defaultValue = { defaultValue }
112+ disablePortal = { disablePortal }
113+ limitTags = { limitTags }
114+ loading = { loading }
115+ loadingText = { loadingText || 'Loading...' }
116+ noOptionsText = { noOptionsText || < i > You have no options to choose from</ i > }
117+ onBlur = { onBlur }
118+ onOpen = { ( ) => setInPlaceholder ( 'Search' ) }
119+ onClose = { ( ) => setInPlaceholder ( placeholder || '' ) }
120+ popupIcon = { < ArrowDropDownIcon /> }
144121 value = { value }
145- onChange = { handleChange }
146122 { ...rest }
123+ onChange = { onChange }
147124 />
148125 )
149126}
0 commit comments