11import {
22 ComponentType ,
3+ ForwardedRef ,
34 forwardRef ,
5+ KeyboardEvent ,
46 useEffect ,
57 useMemo ,
68 useRef ,
@@ -9,7 +11,7 @@ import {
911
1012import { useEvent } from '../../../_internal/hooks' ;
1113import { FieldBaseProps } from '../../../shared' ;
12- import { mergeProps } from '../../../utils/react/index' ;
14+ import { mergeProps , useCombinedRefs } from '../../../utils/react/index' ;
1315import { useFieldProps , useFormProps , wrapWithField } from '../../form' ;
1416import { CloseIcon , PlusIcon } from '../../../icons' ;
1517import { Button } from '../../actions' ;
@@ -63,7 +65,12 @@ function removeDuplicates(mappings: Mapping[]) {
6365 } ) ;
6466}
6567
66- function TextInputMapper ( props : CubeTextInputMapperProps , ref : any ) {
68+ function TextInputMapper (
69+ props : CubeTextInputMapperProps ,
70+ ref : ForwardedRef < HTMLDivElement > ,
71+ ) {
72+ ref = useCombinedRefs ( ref ) ;
73+
6774 props = useFormProps ( props ) ;
6875 props = useFieldProps ( props , {
6976 defaultValidationTrigger : 'onChange' ,
@@ -122,7 +129,7 @@ function TextInputMapper(props: CubeTextInputMapperProps, ref: any) {
122129 const onMappingsChange = useEvent ( ( newMappings : Mapping [ ] ) => {
123130 const newValue = newMappings . reduce (
124131 ( acc , { key, value } ) => {
125- acc [ key ] = value ;
132+ acc [ key . trim ( ) ] = value . trim ( ) ;
126133
127134 return acc ;
128135 } ,
@@ -136,8 +143,25 @@ function TextInputMapper(props: CubeTextInputMapperProps, ref: any) {
136143 } else {
137144 onChange ?.( newValue ) ;
138145 }
146+
147+ const updatedMappings = extractLocalValues ( newValue ?? { } , newMappings ) ;
148+
149+ if ( JSON . stringify ( updatedMappings ) !== JSON . stringify ( mappings ) ) {
150+ setMappings ( updatedMappings ) ;
151+ }
139152 } ) ;
140153
154+ // useEffect(() => {
155+ // // focus on the last non-disabled input
156+ // setTimeout(() => {
157+ // (
158+ // ref?.current?.querySelector(
159+ // '[data-qa="Mapping"]:last-child input:not([disabled])',
160+ // ) as HTMLInputElement
161+ // )?.focus();
162+ // }, 100);
163+ // }, [mappings.length]);
164+
141165 const addNewMapping = useEvent ( ( ) => {
142166 setMappings ( ( prev ) => {
143167 return [ ...prev , { key : '' , value : '' , id : counterRef . current ++ } ] ;
@@ -176,17 +200,26 @@ function TextInputMapper(props: CubeTextInputMapperProps, ref: any) {
176200 onMappingsChange ( mappings ) ;
177201 } ) ;
178202
203+ const onKeyDown = useEvent ( ( e : KeyboardEvent < HTMLDivElement > ) => {
204+ // if Ctrl+Enter or Cmd+Enter is pressed then add new mapping if that's enabled
205+ if ( ( e . ctrlKey || e . metaKey ) && e . key === 'Enter' && showNewButton ) {
206+ addNewMapping ( ) ;
207+ }
208+ } ) ;
209+
179210 const renderedMappings = useMemo ( ( ) => {
180- return mappings . map ( ( mapping ) => {
211+ return mappings . map ( ( mapping , index ) => {
181212 const { key, value, id } = mapping ;
182213
183214 return (
184215 < Grid
185216 key = { id }
217+ qa = "Mapping"
186218 columns = "minmax(0, 1fr) minmax(0, 1fr) min-content"
187219 gap = "1x"
188220 >
189221 < TextInputMapperInput
222+ autoFocus = { index === mappings . length - 1 }
190223 id = { id }
191224 isDisabled = { isDisabled }
192225 type = "name"
@@ -222,8 +255,10 @@ function TextInputMapper(props: CubeTextInputMapperProps, ref: any) {
222255 } , [ JSON . stringify ( mappings ) ] ) ;
223256
224257 const element = (
225- < Flow gap = "1x" >
226- { [ ...renderedMappings ] }
258+ < Flow ref = { ref } gap = "1x" >
259+ < Flow gap = "1x" onKeyDown = { onKeyDown } >
260+ { [ ...renderedMappings ] }
261+ </ Flow >
227262 { showNewButton ? (
228263 < Space gap = { 0 } >
229264 { /** Hotfix for inconsistent alignment with the label **/ }
@@ -251,6 +286,7 @@ export interface CubeTextInputMapperInputProps {
251286 onChange ?: ( id : number , newValue : string ) => void ;
252287 onSubmit ?: ( id : number ) => void ;
253288 isDisabled ?: boolean ;
289+ autoFocus ?: boolean ;
254290}
255291
256292function TextInputMapperInput ( props : CubeTextInputMapperInputProps ) {
0 commit comments