@@ -75,6 +75,7 @@ export const ColumnMappingModal: FC<ColumnMappingModalProps> = ({
75
75
76
76
const openModalButtonText = columnMapping !== null ? 'Edit column mapping' : 'Add column mapping' ;
77
77
const saveButtonText = columnMapping === null ? 'Add this mapping' : 'Save' ;
78
+ const minWidthStyle = calculateMinWidthStyleFromPossibleOptions ( groupedInputFields ) ;
78
79
79
80
return (
80
81
< >
@@ -101,8 +102,8 @@ export const ColumnMappingModal: FC<ColumnMappingModalProps> = ({
101
102
< table >
102
103
< thead >
103
104
< tr >
104
- < th className = 'pr-12 py-2' > Column in your file</ th >
105
- < th className = 'min-w-56' > Submission column</ th >
105
+ < th className = 'pr-16 py-2' > Column in your file</ th >
106
+ < th style = { minWidthStyle } > Submission column</ th >
106
107
</ tr >
107
108
</ thead >
108
109
< tbody >
@@ -184,10 +185,39 @@ export const ColumnSelectorRow: FC<ColumnSelectorRowProps> = ({
184
185
: undefined ;
185
186
const selectedOptionText = selectedField ?. displayName ?? selectedField ?. name ;
186
187
188
+ const minWidthStyle = calculateMinWidthStyleFromPossibleOptions ( options ) ;
189
+
190
+ const inputFieldToListboxOption = ( header : string , field : InputField ) : React . JSX . Element => (
191
+ < ListboxOption
192
+ key = { `${ header } -${ field . name } ` }
193
+ value = { field . name }
194
+ className = { `data-[focus]:bg-primary-200 p-1 pl-3 rounded-sm ${ selectedOption === field . name ? 'bg-gray-200' : '' } ` }
195
+ data-tooltip-id = { `${ header } -${ field . name } -tooltip` }
196
+ >
197
+ < span className = { usedOptions . includes ( field . name ) ? 'text-gray-400' : '' } >
198
+ { field . displayName ?? field . name }
199
+ </ span >
200
+ { ( field . definition ?? field . guidance ) && (
201
+ < Tooltip
202
+ id = { `${ header } -${ field . name } -tooltip` }
203
+ place = 'right'
204
+ positionStrategy = 'fixed'
205
+ className = 'z-20 max-w-80 space-y-2'
206
+ >
207
+ < p >
208
+ < span className = 'font-mono font-semibold text-gray-300' > { field . name } </ span >
209
+ </ p >
210
+ { field . definition && < p > { field . definition } </ p > }
211
+ { field . guidance && < p > { field . guidance } </ p > }
212
+ </ Tooltip >
213
+ ) }
214
+ </ ListboxOption >
215
+ ) ;
216
+
187
217
return (
188
218
< tr key = { selectingFor } className = 'border-gray-400 border-solid border-x-0 border-y' >
189
219
< td className = 'pr-4' > { selectingFor } </ td >
190
- < td >
220
+ < td style = { minWidthStyle } >
191
221
< Listbox
192
222
value = { selectedOption }
193
223
onChange = { ( newValue ) =>
@@ -220,28 +250,7 @@ export const ColumnSelectorRow: FC<ColumnSelectorRowProps> = ({
220
250
return (
221
251
< div key = { header } className = 'pt-1' >
222
252
< div className = 'p-1 font-semibold' > { header } </ div >
223
- { fields . map ( ( field ) => (
224
- < ListboxOption
225
- key = { `${ header } -${ field . name } ` }
226
- value = { field . name }
227
- className = 'data-[focus]:bg-primary-200 p-1 pl-3 rounded-sm'
228
- data-tooltip-id = { `${ header } -${ field . name } -tooltip` }
229
- >
230
- < span className = { usedOptions . includes ( field . name ) ? 'text-gray-400' : '' } >
231
- { field . displayName ?? field . name }
232
- </ span >
233
- { ( field . definition ?? field . guidance ) && (
234
- < Tooltip
235
- id = { `${ header } -${ field . name } -tooltip` }
236
- place = 'right'
237
- positionStrategy = 'fixed'
238
- className = 'z-20 max-w-80'
239
- >
240
- { field . definition } { field . guidance }
241
- </ Tooltip >
242
- ) }
243
- </ ListboxOption >
244
- ) ) }
253
+ { fields . map ( ( field ) => inputFieldToListboxOption ( header , field ) ) }
245
254
</ div >
246
255
) ;
247
256
} ) }
@@ -251,3 +260,16 @@ export const ColumnSelectorRow: FC<ColumnSelectorRowProps> = ({
251
260
</ tr >
252
261
) ;
253
262
} ;
263
+
264
+ /* Estimate the min width of a column with select for these input fields,
265
+ * so you don't get layout shifts when selecting different, longer, values. */
266
+ function calculateMinWidthStyleFromPossibleOptions ( options : Map < string , InputField [ ] > ) : React . CSSProperties {
267
+ const maxOptionTextLength = Math . max (
268
+ ...Array . from ( options . values ( ) )
269
+ . flat ( )
270
+ . flatMap ( ( x ) => [ x . name , x . displayName ] )
271
+ . map ( ( text ) => text ?. length ?? 0 ) ,
272
+ ) ;
273
+
274
+ return { minWidth : `${ Math . ceil ( maxOptionTextLength / 2 ) + 2 } rem` } ;
275
+ }
0 commit comments