66 RefObject ,
77 useEffect ,
88 useMemo ,
9- useState ,
109} from 'react' ;
1110import {
1211 useButton ,
@@ -111,7 +110,7 @@ export interface CubeComboBoxProps<T>
111110 AriaTextFieldProps {
112111 defaultSelectedKey ?: string ;
113112 selectedKey ?: string ;
114- onSelectionChange ?: ( selectedKey : string ) => void ;
113+ onSelectionChange ?: ( selectedKey : string | null ) => void ;
115114 onInputChange ?: ( inputValue : string ) => void ;
116115 inputValue ?: string ;
117116 placeholder ?: string ;
@@ -147,22 +146,26 @@ export const ComboBox = forwardRef(function ComboBox<T extends object>(
147146 props = useFieldProps ( props , {
148147 valuePropsMapper : ( { value, onChange } ) => {
149148 return {
150- selectedKey : value ?? null ,
151- onSelectionChange ( val : string ) {
152- setIsEmptyStateAllowed ( false ) ;
149+ selectedKey : ! props . allowsCustomValue ? value ?? null : undefined ,
150+ inputValue : props . allowsCustomValue ? value ?? '' : undefined ,
151+ onInputChange ( val ) {
152+ if ( ! props . allowsCustomValue ) {
153+ return ;
154+ }
153155
154- if ( val != null ) {
155- onChange ( val ) ;
156- } else {
157- onChange ( inputRef ?. current ?. value ) ;
156+ onChange ( val ) ;
157+ } ,
158+ onSelectionChange ( val : string ) {
159+ if ( val == null && props . allowsCustomValue ) {
160+ return ;
158161 }
162+
163+ onChange ( val ) ;
159164 } ,
160165 } ;
161166 } ,
162167 } ) ;
163168
164- const [ isEmptyStateAllowed , setIsEmptyStateAllowed ] = useState ( false ) ;
165-
166169 let {
167170 qa,
168171 label,
@@ -326,43 +329,55 @@ export const ComboBox = forwardRef(function ComboBox<T extends object>(
326329
327330 // If input is not full and the user presses Enter, pick the first option.
328331 let onKeyPress = useEvent ( ( e : KeyboardEvent ) => {
329- if ( e . key === 'Enter' && ! props . allowsCustomValue && state . isOpen ) {
330- const option = [ ...state . collection ] [ 0 ] ?. key ;
332+ if ( e . key === 'Enter' ) {
333+ if ( ! props . allowsCustomValue && state . isOpen ) {
334+ const inputValue = inputRef ?. current ?. value ;
331335
332- if ( option && selectedKey !== option ) {
333- props . onSelectionChange ?.( option ) ;
336+ if ( inputValue === '' ) {
337+ state . close ( ) ;
338+ props . onSelectionChange ?.( null ) ;
334339
335- e . stopPropagation ( ) ;
336- e . preventDefault ( ) ;
337- }
338- }
339- } ) ;
340+ e . stopPropagation ( ) ;
341+ e . preventDefault ( ) ;
342+ } else {
343+ const option = [ ...state . collection ] [ 0 ] ?. key ;
340344
341- let onChange = useEvent ( ( ) => {
342- if ( ! inputRef ?. current ?. value && props . allowsCustomValue ) {
343- setIsEmptyStateAllowed ( true ) ;
344- }
345- } ) ;
345+ if ( option && selectedKey !== option ) {
346+ props . onSelectionChange ?.( option ) ;
347+
348+ e . stopPropagation ( ) ;
349+ e . preventDefault ( ) ;
350+ }
351+ }
352+ // If a custom value is allowed, we need to check if the input value is in the collection.
353+ } else if ( props . allowsCustomValue ) {
354+ const inputValue = inputRef ?. current ?. value ;
355+
356+ const item = [ ...state . collection ] . find (
357+ ( item ) => item . textValue === inputValue ,
358+ ) ;
346359
347- let onBlur = useEvent ( ( ) => {
348- setIsEmptyStateAllowed ( false ) ;
360+ props . onSelectionChange ?.(
361+ item ? item . key : inputRef ?. current ?. value ?? '' ,
362+ ) ;
363+
364+ if ( item && inputRef ?. current ) {
365+ inputRef . current . value = item . key ;
366+ }
367+ }
368+ }
349369 } ) ;
350370
351371 useEffect ( ( ) => {
352372 inputRef . current ?. addEventListener ( 'keydown' , onKeyPress , true ) ;
353- inputRef . current ?. addEventListener ( 'input' , onChange , true ) ;
354373
355374 return ( ) => {
356375 inputRef . current ?. removeEventListener ( 'keydown' , onKeyPress , true ) ;
357- inputRef . current ?. removeEventListener ( 'input' , onChange , true ) ;
358376 } ;
359377 } , [ ] ) ;
360378
361379 let allInputProps = useMemo (
362- ( ) =>
363- mergeProps ( inputProps , hoverProps , focusProps , {
364- onBlur,
365- } ) ,
380+ ( ) => mergeProps ( inputProps , hoverProps , focusProps ) ,
366381 [ inputProps , hoverProps , focusProps ] ,
367382 ) ;
368383
@@ -383,11 +398,6 @@ export const ComboBox = forwardRef(function ComboBox<T extends object>(
383398 autoFocus = { autoFocus }
384399 data-autofocus = { autoFocus ? '' : undefined }
385400 { ...allInputProps }
386- value = {
387- isEmptyStateAllowed || allInputProps . value || ! props . allowsCustomValue
388- ? allInputProps . value
389- : selectedKey
390- }
391401 autoComplete = { autoComplete }
392402 styles = { inputStyles }
393403 { ...modAttrs ( mods ) }
0 commit comments