@@ -11,14 +11,17 @@ import {
1111
1212import { useEvent } from '../../../_internal/hooks' ;
1313import { FieldBaseProps } from '../../../shared' ;
14- import { mergeProps , useCombinedRefs } from '../../../utils/react/index ' ;
14+ import { mergeProps , useCombinedRefs } from '../../../utils/react' ;
1515import { useFieldProps , useFormProps , wrapWithField } from '../../form' ;
1616import { CloseIcon , PlusIcon } from '../../../icons' ;
1717import { Button } from '../../actions' ;
1818import { Block } from '../../Block' ;
1919import { Flow } from '../../layout/Flow' ;
2020import { Grid } from '../../layout/Grid' ;
2121import { Space } from '../../layout/Space' ;
22+ import { ComboBox } from '../ComboBox' ;
23+ import { PasswordInput } from '../PasswordInput/PasswordInput' ;
24+ import { TextArea } from '../TextArea/index' ;
2225import { TextInput } from '../TextInput' ;
2326
2427type Mapping = {
@@ -32,9 +35,11 @@ export interface CubeTextInputMapperProps extends FieldBaseProps {
3235 isDisabled ?: boolean ;
3336 value ?: Record < string , string > ;
3437 onChange ?: ( value : Record < string , string > | undefined ) => void ;
38+ KeyComponent ?: ComponentType < CubeTextInputMapperInputProps > ;
3539 ValueComponent ?: ComponentType < CubeTextInputMapperInputProps > ;
3640 keyProps ?: Partial < CubeTextInputMapperInputProps > ;
3741 valueProps ?: Partial < CubeTextInputMapperInputProps > ;
42+ allowsCustomValue ?: boolean ;
3843}
3944
4045// Rewrites upper level field component styles
@@ -89,6 +94,7 @@ function TextInputMapper(
8994 onChange,
9095 keyProps,
9196 valueProps,
97+ KeyComponent,
9298 ValueComponent,
9399 } = props ;
94100
@@ -174,6 +180,7 @@ function TextInputMapper(
174180 ) ;
175181 } , [ mappings ] ) ;
176182
183+ KeyComponent = KeyComponent ?? TextInputMapperInput ;
177184 ValueComponent = ValueComponent ?? TextInputMapperInput ;
178185
179186 const onKeyChange = useEvent ( ( id : number , value : string ) => {
@@ -218,11 +225,11 @@ function TextInputMapper(
218225 columns = "minmax(0, 1fr) minmax(0, 1fr) min-content"
219226 gap = "1x"
220227 >
221- < TextInputMapperInput
228+ < KeyComponent
222229 autoFocus = { index === mappings . length - 1 }
223230 id = { id }
224231 isDisabled = { isDisabled }
225- type = "name "
232+ fieldType = "key "
226233 value = { key }
227234 placeholder = "Key"
228235 onChange = { onKeyChange }
@@ -231,7 +238,7 @@ function TextInputMapper(
231238 />
232239 < ValueComponent
233240 id = { id }
234- type = "value"
241+ fieldType = "value"
235242 isDisabled = { ! key || isDisabled }
236243 value = { value }
237244 placeholder = "Value"
@@ -278,17 +285,29 @@ function TextInputMapper(
278285
279286export interface CubeTextInputMapperInputProps {
280287 id : number ;
281- type : 'name' | 'value' ;
288+ fieldType : 'key' | 'value' ;
289+ inputType ?: 'input' | 'combobox' | 'password' | 'textarea' ;
282290 value ?: string ;
291+ options ?: string [ ] ;
283292 placeholder ?: string ;
284293 onChange ?: ( id : number , newValue : string ) => void ;
285294 onSubmit ?: ( id : number ) => void ;
286295 isDisabled ?: boolean ;
287296 autoFocus ?: boolean ;
297+ allowsCustomValue ?: boolean ;
288298}
289299
290300function TextInputMapperInput ( props : CubeTextInputMapperInputProps ) {
291- const { id, type, value, placeholder, ...rest } = props ;
301+ const {
302+ id,
303+ fieldType,
304+ inputType = 'input' ,
305+ options,
306+ value,
307+ placeholder,
308+ allowsCustomValue,
309+ ...rest
310+ } = props ;
292311
293312 const onChange = useEvent ( ( newValue : string ) => {
294313 props . onChange ?.( id , newValue ) ;
@@ -298,10 +317,51 @@ function TextInputMapperInput(props: CubeTextInputMapperInputProps) {
298317 props . onSubmit ?.( id ) ;
299318 } ) ;
300319
320+ const onSelectionChange = useEvent ( ( newValue : string ) => {
321+ if ( ! allowsCustomValue && ! options ?. includes ( newValue ) ) {
322+ props . onChange ?.( id , '' ) ;
323+ } else {
324+ props . onChange ?.( id , newValue ) ;
325+ }
326+
327+ props . onSubmit ?.( id ) ;
328+ } ) ;
329+
330+ const Component = {
331+ input : TextInput ,
332+ textarea : TextArea ,
333+ password : PasswordInput ,
334+ } [ inputType ] ;
335+
336+ if ( inputType === 'combobox' ) {
337+ return (
338+ < ComboBox
339+ qa = "AddMapping"
340+ data-type = { fieldType }
341+ width = "auto"
342+ { ...mergeProps ( rest , PROPS_GRID_HACK ) }
343+ id = { undefined }
344+ inputValue = { value }
345+ selectedKey = { value }
346+ labelPosition = "top"
347+ aria-label = { placeholder }
348+ placeholder = { placeholder }
349+ onInputChange = { onChange }
350+ onSelectionChange = { onSelectionChange }
351+ >
352+ { ( options ?? [ ] ) . map ( ( option ) => (
353+ < ComboBox . Item key = { option } > { option } </ ComboBox . Item >
354+ ) ) }
355+ </ ComboBox >
356+ ) ;
357+ }
358+
301359 return (
302- < TextInput
360+ < Component
303361 qa = "AddMapping"
362+ data-type = { fieldType }
304363 width = "auto"
364+ rows = { 1 }
305365 { ...mergeProps ( rest , PROPS_GRID_HACK ) }
306366 id = { undefined }
307367 value = { value }
0 commit comments