@@ -34,6 +34,17 @@ import type { PropsFromGenericComponent } from 'src/layout';
34
34
import type { IDataModelBindingsForList } from 'src/layout/List/config.generated' ;
35
35
36
36
type Row = Record < string , string | number | boolean > ;
37
+ type SelectionMode = 'readonly' | 'single' | 'multiple' ;
38
+
39
+ function getSelectionMode ( bindings : IDataModelBindingsForList ) : SelectionMode {
40
+ const hasValidBindings = Object . keys ( bindings ) . length > 0 && Object . values ( bindings ) . some ( ( b ) => b !== undefined ) ;
41
+
42
+ if ( ! hasValidBindings ) {
43
+ return 'readonly' ;
44
+ }
45
+
46
+ return bindings . group ? 'multiple' : 'single' ;
47
+ }
37
48
38
49
export const ListComponent = ( { baseComponentId } : PropsFromGenericComponent < 'List' > ) => {
39
50
const isMobile = useIsMobile ( ) ;
@@ -66,14 +77,19 @@ export const ListComponent = ({ baseComponentId }: PropsFromGenericComponent<'Li
66
77
const { data } = useDataListQuery ( filter , dataListId , secure , mapping , queryParameters ) ;
67
78
const bindings = item . dataModelBindings ?? ( { } as IDataModelBindingsForList ) ;
68
79
80
+ // Determine selection mode based on bindings
81
+ const selectionMode = getSelectionMode ( bindings ) ;
82
+ const readOnly = selectionMode === 'readonly' ;
83
+ const isMultipleSelection = selectionMode === 'multiple' ;
84
+
69
85
const { formData, setValues } = useDataModelBindings ( bindings , DEFAULT_DEBOUNCE_TIMEOUT , 'raw' ) ;
70
- const { toggle, isChecked, enabled } = useSaveObjectToGroup ( bindings ) ;
86
+ const { toggle, isChecked } = useSaveObjectToGroup ( bindings ) ;
71
87
72
88
const tableHeadersToShowInMobile = Object . keys ( tableHeaders ) . filter (
73
89
( key ) => ! tableHeadersMobile || tableHeadersMobile . includes ( key ) ,
74
90
) ;
75
91
76
- const selectedRow = ! enabled
92
+ const selectedRow = ! isMultipleSelection
77
93
? ( data ?. listItems . find ( ( row ) => Object . keys ( formData ) . every ( ( key ) => row [ key ] === formData [ key ] ) ) ?? '' )
78
94
: '' ;
79
95
@@ -86,7 +102,7 @@ export const ListComponent = ({ baseComponentId }: PropsFromGenericComponent<'Li
86
102
}
87
103
88
104
function isRowSelected ( row : Row ) : boolean {
89
- if ( enabled ) {
105
+ if ( isMultipleSelection ) {
90
106
return isChecked ( row ) ;
91
107
}
92
108
return JSON . stringify ( selectedRow ) === JSON . stringify ( row ) ;
@@ -96,7 +112,11 @@ export const ListComponent = ({ baseComponentId }: PropsFromGenericComponent<'Li
96
112
const description = item . textResourceBindings ?. description ;
97
113
98
114
const handleRowClick = ( row : Row ) => {
99
- if ( enabled ) {
115
+ if ( readOnly ) {
116
+ return ;
117
+ }
118
+
119
+ if ( isMultipleSelection ) {
100
120
toggle ( row ) ;
101
121
} else {
102
122
handleSelectedRadioRow ( { selectedValue : row } ) ;
@@ -151,10 +171,10 @@ export const ListComponent = ({ baseComponentId }: PropsFromGenericComponent<'Li
151
171
required,
152
172
} ) ;
153
173
154
- if ( isMobile ) {
174
+ if ( isMobile && ! readOnly ) {
155
175
return (
156
176
< ComponentStructureWrapper baseComponentId = { baseComponentId } >
157
- { enabled ? (
177
+ { isMultipleSelection ? (
158
178
< Fieldset >
159
179
< Fieldset . Legend >
160
180
{ description && (
@@ -170,17 +190,19 @@ export const ListComponent = ({ baseComponentId }: PropsFromGenericComponent<'Li
170
190
< RequiredIndicator required = { required } />
171
191
</ Heading >
172
192
</ Fieldset . Legend >
173
- { data ?. listItems . map ( ( row ) => (
174
- < Checkbox
175
- key = { JSON . stringify ( row ) }
176
- className = { cn ( classes . mobile ) }
177
- { ...getCheckboxProps ( { value : JSON . stringify ( row ) } ) }
178
- onClick = { ( ) => handleRowClick ( row ) }
179
- value = { JSON . stringify ( row ) }
180
- checked = { isChecked ( row ) }
181
- label = { renderListItems ( row , tableHeaders ) }
182
- />
183
- ) ) }
193
+ < div >
194
+ { data ?. listItems . map ( ( row , idx ) => (
195
+ < Checkbox
196
+ key = { idx }
197
+ className = { cn ( classes . mobile ) }
198
+ { ...getCheckboxProps ( { value : JSON . stringify ( row ) } ) }
199
+ onClick = { ( ) => handleRowClick ( row ) }
200
+ value = { JSON . stringify ( row ) }
201
+ checked = { isChecked ( row ) }
202
+ label = { renderListItems ( row , tableHeaders ) }
203
+ />
204
+ ) ) }
205
+ </ div >
184
206
</ Fieldset >
185
207
) : (
186
208
< Fieldset className = { classes . mobileGroup } >
@@ -199,9 +221,9 @@ export const ListComponent = ({ baseComponentId }: PropsFromGenericComponent<'Li
199
221
</ Fieldset . Description >
200
222
) }
201
223
202
- { data ?. listItems . map ( ( row ) => (
224
+ { data ?. listItems . map ( ( row , idx ) => (
203
225
< Radio
204
- key = { JSON . stringify ( row ) }
226
+ key = { idx }
205
227
{ ...getRadioProps ( { value : JSON . stringify ( row ) } ) }
206
228
value = { JSON . stringify ( row ) }
207
229
className = { cn ( classes . mobile , { [ classes . selectedRow ] : isRowSelected ( row ) } ) }
@@ -246,11 +268,13 @@ export const ListComponent = ({ baseComponentId }: PropsFromGenericComponent<'Li
246
268
) }
247
269
< Table . Head >
248
270
< Table . Row >
249
- < Table . HeaderCell >
250
- < span className = { utilClasses . visuallyHidden } >
251
- < Lang id = 'list_component.controlsHeader' />
252
- </ span >
253
- </ Table . HeaderCell >
271
+ { ! readOnly && (
272
+ < Table . HeaderCell >
273
+ < span className = { utilClasses . visuallyHidden } >
274
+ < Lang id = 'list_component.controlsHeader' />
275
+ </ span >
276
+ </ Table . HeaderCell >
277
+ ) }
254
278
{ Object . entries ( tableHeaders ) . map ( ( [ key , value ] ) => {
255
279
const isSortable = sortableColumns ?. includes ( key ) ;
256
280
let sort : AriaAttributes [ 'aria-sort' ] = undefined ;
@@ -273,41 +297,44 @@ export const ListComponent = ({ baseComponentId }: PropsFromGenericComponent<'Li
273
297
{ data ?. listItems . map ( ( row ) => (
274
298
< Table . Row
275
299
key = { JSON . stringify ( row ) }
276
- onClick = { ( ) => handleRowClick ( row ) }
300
+ onClick = { ! readOnly ? ( ) => handleRowClick ( row ) : undefined }
301
+ className = { cn ( { [ classes . readOnlyRow ] : readOnly } ) }
277
302
>
278
- < Table . Cell
279
- className = { cn ( {
280
- [ classes . selectedRowCell ] : isRowSelected ( row ) ,
281
- } ) }
282
- >
283
- { enabled ? (
284
- < Checkbox
285
- className = { classes . toggleControl }
286
- label = { < span className = 'sr-only' > { getRowLabel ( row ) } </ span > }
287
- onChange = { ( ) => { } }
288
- value = { JSON . stringify ( row ) }
289
- checked = { isChecked ( row ) }
290
- name = { indexedId }
291
- />
292
- ) : (
293
- < RadioButton
294
- className = { classes . toggleControl }
295
- label = { getRowLabel ( row ) }
296
- hideLabel
297
- onChange = { ( ) => {
298
- handleSelectedRadioRow ( { selectedValue : row } ) ;
299
- } }
300
- value = { JSON . stringify ( row ) }
301
- checked = { isRowSelected ( row ) }
302
- name = { indexedId }
303
- />
304
- ) }
305
- </ Table . Cell >
303
+ { ! readOnly && (
304
+ < Table . Cell
305
+ className = { cn ( {
306
+ [ classes . selectedRowCell ] : isRowSelected ( row ) && ! readOnly ,
307
+ } ) }
308
+ >
309
+ { isMultipleSelection ? (
310
+ < Checkbox
311
+ className = { classes . toggleControl }
312
+ label = { < span className = 'sr-only' > { getRowLabel ( row ) } </ span > }
313
+ onChange = { ( ) => toggle ( row ) }
314
+ onClick = { ( e ) => e . stopPropagation ( ) }
315
+ value = { JSON . stringify ( row ) }
316
+ checked = { isChecked ( row ) }
317
+ name = { indexedId }
318
+ />
319
+ ) : (
320
+ < RadioButton
321
+ className = { classes . toggleControl }
322
+ label = { getRowLabel ( row ) }
323
+ hideLabel
324
+ onChange = { ( ) => handleSelectedRadioRow ( { selectedValue : row } ) }
325
+ onClick = { ( e ) => e . stopPropagation ( ) }
326
+ value = { JSON . stringify ( row ) }
327
+ checked = { isRowSelected ( row ) }
328
+ name = { indexedId }
329
+ />
330
+ ) }
331
+ </ Table . Cell >
332
+ ) }
306
333
{ Object . keys ( tableHeaders ) . map ( ( key ) => (
307
334
< Table . Cell
308
335
key = { key }
309
336
className = { cn ( {
310
- [ classes . selectedRowCell ] : isRowSelected ( row ) ,
337
+ [ classes . selectedRowCell ] : isRowSelected ( row ) && ! readOnly ,
311
338
} ) }
312
339
>
313
340
{ typeof row [ key ] === 'string' ? < Lang id = { row [ key ] } /> : row [ key ] }
0 commit comments