@@ -37,6 +37,7 @@ import React, { createRef, useEffect, useRef, useState } from 'react'
37
37
import { ReactComponent as ICArrowDown } from '../../../Assets/Icon/ic-arrow-down.svg'
38
38
import { ReactComponent as ICCross } from '../../../Assets/Icon/ic-cross.svg'
39
39
import { ResizableTagTextArea , SortingOrder , useStateFilters } from '../../../Common'
40
+ import { stringComparatorBySortOrder } from '../../Helpers'
40
41
import { KeyValueRow , KeyValueTableProps } from './KeyValueTable.types'
41
42
42
43
import './KeyValueTable.scss'
@@ -48,6 +49,7 @@ export const KeyValueTable = <K extends string>({
48
49
headerComponent,
49
50
onChange,
50
51
onDelete,
52
+ placeholder,
51
53
isAdditionNotAllowed,
52
54
} : KeyValueTableProps < K > ) => {
53
55
// CONSTANTS
@@ -64,33 +66,20 @@ export const KeyValueTable = <K extends string>({
64
66
initialSortKey : firstHeaderKey ,
65
67
} )
66
68
const inputRowRef = useRef < HTMLTextAreaElement > ( )
67
- const keyTextAreaRef = useRef < React . RefObject < HTMLTextAreaElement > [ ] > ( [ ] )
68
- const valueTextAreaRef = useRef < React . RefObject < HTMLTextAreaElement > [ ] > ( [ ] )
69
+ const keyTextAreaRef = useRef < Record < string , React . RefObject < HTMLTextAreaElement > > > ( )
70
+ const valueTextAreaRef = useRef < Record < string , React . RefObject < HTMLTextAreaElement > > > ( )
69
71
70
- useEffect ( ( ) => {
71
- if ( keyTextAreaRef . current . length !== _rows . length ) {
72
- keyTextAreaRef . current = new Array ( _rows . length )
73
- . fill ( 0 )
74
- . map ( ( _ , i ) => keyTextAreaRef . current [ i ] || createRef < HTMLTextAreaElement > ( ) )
75
- }
72
+ if ( ! keyTextAreaRef . current ) {
73
+ keyTextAreaRef . current = _rows . reduce ( ( acc , curr ) => ( { ...acc , [ curr . id ] : createRef ( ) } ) , { } )
74
+ }
76
75
77
- if ( valueTextAreaRef . current . length !== _rows . length ) {
78
- valueTextAreaRef . current = new Array ( _rows . length )
79
- . fill ( 0 )
80
- . map ( ( _ , i ) => valueTextAreaRef . current [ i ] || createRef < HTMLTextAreaElement > ( ) )
81
- }
82
- } , [ ] )
76
+ if ( ! valueTextAreaRef . current ) {
77
+ valueTextAreaRef . current = _rows . reduce ( ( acc , curr ) => ( { ...acc , [ curr . id ] : createRef ( ) } ) , { } )
78
+ }
83
79
84
80
useEffect ( ( ) => {
85
- const sortFn = ( a : KeyValueRow < K > , b : KeyValueRow < K > ) => {
86
- if ( sortOrder === SortingOrder . ASC ) {
87
- return b . data [ sortBy ] . value . localeCompare ( a . data [ sortBy ] . value )
88
- }
89
- return a . data [ sortBy ] . value . localeCompare ( b . data [ sortBy ] . value )
90
- }
91
-
92
81
const sortedRows = [ ..._rows ]
93
- sortedRows . sort ( sortFn )
82
+ sortedRows . sort ( ( a , b ) => stringComparatorBySortOrder ( a . data [ sortBy ] . value , b . data [ sortBy ] . value , sortOrder ) )
94
83
setRows ( sortedRows )
95
84
} , [ sortOrder ] )
96
85
@@ -101,45 +90,51 @@ export const KeyValueTable = <K extends string>({
101
90
102
91
if (
103
92
! firstRow . data [ secondHeaderKey ] . value &&
104
- keyTextAreaRef . current [ 0 ] . current &&
105
- valueTextAreaRef . current [ 0 ] . current
93
+ keyTextAreaRef . current [ firstRow . id ] . current &&
94
+ valueTextAreaRef . current [ firstRow . id ] . current
106
95
) {
107
- keyTextAreaRef . current [ 0 ] . current . focus ( )
96
+ keyTextAreaRef . current [ firstRow . id ] . current . focus ( )
108
97
}
109
98
if (
110
99
! firstRow . data [ firstHeaderKey ] . value &&
111
- valueTextAreaRef . current [ 0 ] . current &&
112
- valueTextAreaRef . current [ 0 ] . current
100
+ keyTextAreaRef . current [ firstRow . id ] . current &&
101
+ valueTextAreaRef . current [ firstRow . id ] . current
113
102
) {
114
- valueTextAreaRef . current [ 0 ] . current . focus ( )
103
+ valueTextAreaRef . current [ firstRow . id ] . current . focus ( )
115
104
}
116
105
}
117
106
} , [ _rows , newRowAdded ] )
118
107
119
108
// METHODS
120
109
const onSortBtnClick = ( ) => handleSorting ( sortBy )
121
110
122
- const onNewRowEdit = ( key : K ) => ( e : React . ChangeEvent < HTMLTextAreaElement > ) => {
111
+ const onNewRowAdd = ( key : K ) => ( e : React . ChangeEvent < HTMLTextAreaElement > ) => {
123
112
const { value } = e . target
124
113
114
+ const id = Date . now ( ) . toString ( 16 )
125
115
const data = {
126
116
data : {
127
117
[ firstHeaderKey ] : {
128
118
value : key === firstHeaderKey ? value : '' ,
129
- placeholder : 'Enter Key' ,
130
119
} ,
131
120
[ secondHeaderKey ] : {
132
121
value : key === secondHeaderKey ? value : '' ,
133
- placeholder : 'Enter Value' ,
134
122
} ,
135
123
} ,
136
- id : Date . now ( ) * Math . random ( ) ,
124
+ id,
137
125
} as KeyValueRow < K >
138
126
139
127
setNewRowAdded ( true )
140
128
setRows ( [ data , ..._rows ] )
141
- keyTextAreaRef . current = [ createRef ( ) , ...keyTextAreaRef . current ]
142
- valueTextAreaRef . current = [ createRef ( ) , ...valueTextAreaRef . current ]
129
+
130
+ keyTextAreaRef . current = {
131
+ ...keyTextAreaRef . current ,
132
+ [ id ] : createRef ( ) ,
133
+ }
134
+ valueTextAreaRef . current = {
135
+ ...valueTextAreaRef . current ,
136
+ [ id ] : createRef ( ) ,
137
+ }
143
138
}
144
139
145
140
const onRowDataEdit =
@@ -150,8 +145,9 @@ export const KeyValueTable = <K extends string>({
150
145
if ( ! value && ! row . data [ key === firstHeaderKey ? secondHeaderKey : firstHeaderKey ] . value ) {
151
146
newRows = _rows . filter ( ( _ , idx ) => idx !== rowIndex )
152
147
153
- keyTextAreaRef . current = keyTextAreaRef . current . filter ( ( _ , idx ) => idx !== rowIndex )
154
- valueTextAreaRef . current = valueTextAreaRef . current . filter ( ( _ , idx ) => idx !== rowIndex )
148
+ delete keyTextAreaRef . current [ row . id ]
149
+ delete valueTextAreaRef . current [ row . id ]
150
+
155
151
if ( inputRowRef . current ) {
156
152
inputRowRef . current . focus ( )
157
153
}
@@ -171,15 +167,26 @@ export const KeyValueTable = <K extends string>({
171
167
..._rows . slice ( rowIndex + 1 ) ,
172
168
]
173
169
}
170
+
174
171
setRows ( newRows )
175
172
onChange ?.( rowIndex , key , value )
176
173
}
177
174
175
+ const onRowDelete = ( rowIndex : number , row : KeyValueRow < K > ) => ( e : React . MouseEvent < HTMLButtonElement > ) => {
176
+ const newRows = _rows . filter ( ( _ , idx ) => idx !== rowIndex )
177
+ setRows ( newRows )
178
+
179
+ delete keyTextAreaRef . current [ row . id ]
180
+ delete valueTextAreaRef . current [ row . id ]
181
+
182
+ onDelete ?.( e , rowIndex )
183
+ }
184
+
178
185
return (
179
186
< div style = { { minHeight : '500px' , background : 'white' , padding : '2px' } } >
180
187
< div className = "dc__border br-4 w-100 table-container" >
181
188
< div
182
- className = " table-row flexbox dc__align-items-center bcn-50 dc__border-bottom"
189
+ className = { ` table-row flexbox dc__align-items-center bcn-50 ${ ! isAdditionNotAllowed || _rows . length ? ' dc__border-bottom' : '' } ` }
183
190
style = { { borderColor : 'var(--N100)' } }
184
191
>
185
192
{ headers . map ( ( { key, label, className } ) =>
@@ -211,7 +218,7 @@ export const KeyValueTable = <K extends string>({
211
218
</ div >
212
219
{ ! isAdditionNotAllowed && (
213
220
< div
214
- className = " table-row flexbox dc__align-items-center dc__border-bottom"
221
+ className = { ` table-row flexbox dc__align-items-center ${ _rows . length ? ' dc__border-bottom' : '' } ` }
215
222
style = { { borderColor : 'var(--N100)' } }
216
223
>
217
224
{ headers . map ( ( { key } ) => (
@@ -224,22 +231,22 @@ export const KeyValueTable = <K extends string>({
224
231
className = "table-input table-input__text-area pt-8 pb-8 pl-10 pb-10 lh-20 fs-13 fw-4"
225
232
value = ""
226
233
rows = { 1 }
227
- placeholder = { key === firstHeaderKey ? 'Enter Key' : 'Enter Value' }
228
- onChange = { onNewRowEdit ( key ) }
234
+ placeholder = { placeholder [ key ] }
235
+ onChange = { onNewRowAdd ( key ) }
229
236
/>
230
237
</ div >
231
238
) ) }
232
239
</ div >
233
240
) }
234
- { _rows ? .map ( ( row , index ) => (
241
+ { _rows . map ( ( row , index ) => (
235
242
< div
236
- key = { ` ${ index . toString ( ) } ` }
243
+ key = { row . id }
237
244
className = { `table-row flexbox dc__align-items-center ${ index !== _rows . length - 1 ? 'dc__border-bottom' : '' } ` }
238
245
style = { { borderColor : 'var(--N100)' } }
239
246
>
240
- { headers . map ( ( { key } , i ) => (
247
+ { headers . map ( ( { key } ) => (
241
248
< div
242
- key = { ` ${ index . toString ( ) } - ${ i . toString ( ) } ` }
249
+ key = { key }
243
250
className = { `cn-9 fs-13 lh-20 py-8 px-12 dc__overflow-auto flexbox dc__align-items-center dc__gap-4 ${ key === firstHeaderKey ? 'head__key' : 'flex-grow-1' } ` }
244
251
>
245
252
{ maskValue ?. [ key ] && row . data [ key ] . value ? (
@@ -252,16 +259,17 @@ export const KeyValueTable = <K extends string>({
252
259
minHeight = { 20 }
253
260
maxHeight = { 144 }
254
261
value = { row . data [ key ] . value }
262
+ placeholder = { placeholder [ key ] }
255
263
onChange = { onRowDataEdit ( row , key , index ) }
256
264
refVar = {
257
265
key === firstHeaderKey
258
- ? keyTextAreaRef . current [ index ]
259
- : valueTextAreaRef . current [ index ]
266
+ ? keyTextAreaRef . current ?. [ row . id ]
267
+ : valueTextAreaRef . current ?. [ row . id ]
260
268
}
261
269
dependentRef = {
262
270
key === firstHeaderKey
263
- ? valueTextAreaRef . current [ index ]
264
- : keyTextAreaRef . current [ index ]
271
+ ? valueTextAreaRef . current ?. [ row . id ]
272
+ : keyTextAreaRef . current ?. [ row . id ]
265
273
}
266
274
disableOnBlurResizeToMinHeight
267
275
/>
@@ -272,12 +280,16 @@ export const KeyValueTable = <K extends string>({
272
280
) }
273
281
</ div >
274
282
) ) }
275
- < div className = "icon flex dc__no-shrink py-10 px-8" >
283
+ < button
284
+ type = "button"
285
+ className = " dc__unset-button-styles icon flex dc__no-shrink py-10 px-8"
286
+ onClick = { onRowDelete ( index , row ) }
287
+ >
276
288
< ICCross
277
- onClick = { ( e ) => onDelete ?. ( e , index ) }
278
- className = "icon-dim-16 fcn-4 dc__align-self-start"
289
+ aria-label = "delete-data"
290
+ className = "icon-dim-16 fcn-4 dc__align-self-start cursor "
279
291
/>
280
- </ div >
292
+ </ button >
281
293
</ div >
282
294
) ) }
283
295
</ div >
0 commit comments