@defra/forms-engine-plugin 4.0.5 → 4.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.public/stylesheets/application.min.css +2 -2
- package/.public/stylesheets/application.min.css.map +1 -1
- package/.server/client/stylesheets/_location-input.scss +60 -0
- package/.server/client/stylesheets/application.scss +1 -6
- package/.server/client/stylesheets/shared.scss +8 -0
- package/.server/server/forms/register-as-a-unicorn-breeder.yaml +28 -0
- package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -1
- package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
- package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +121 -0
- package/.server/server/plugins/engine/components/EastingNorthingField.js +166 -0
- package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -0
- package/.server/server/plugins/engine/components/LatLongField.d.ts +121 -0
- package/.server/server/plugins/engine/components/LatLongField.js +164 -0
- package/.server/server/plugins/engine/components/LatLongField.js.map +1 -0
- package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +134 -0
- package/.server/server/plugins/engine/components/LocationFieldBase.js +85 -0
- package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -0
- package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +108 -0
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js +96 -0
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -0
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +19 -0
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +40 -0
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -0
- package/.server/server/plugins/engine/components/OsGridRefField.d.ts +19 -0
- package/.server/server/plugins/engine/components/OsGridRefField.js +56 -0
- package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -0
- package/.server/server/plugins/engine/components/helpers/components.d.ts +3 -4
- package/.server/server/plugins/engine/components/helpers/components.js +21 -29
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
- package/.server/server/plugins/engine/components/index.d.ts +4 -0
- package/.server/server/plugins/engine/components/index.js +4 -0
- package/.server/server/plugins/engine/components/index.js.map +1 -1
- package/.server/server/plugins/engine/components/markdownParser.d.ts +2 -0
- package/.server/server/plugins/engine/components/markdownParser.js +28 -0
- package/.server/server/plugins/engine/components/markdownParser.js.map +1 -0
- package/.server/server/plugins/engine/components/types.d.ts +10 -0
- package/.server/server/plugins/engine/components/types.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js +7 -0
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js.map +1 -1
- package/.server/server/plugins/engine/types/index.d.ts +1 -1
- package/.server/server/plugins/engine/types/index.js.map +1 -1
- package/.server/server/plugins/engine/types.d.ts +2 -2
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/plugins/engine/views/components/_location-field-base.html +53 -0
- package/.server/server/plugins/engine/views/components/eastingnorthingfield.html +5 -0
- package/.server/server/plugins/engine/views/components/latlongfield.html +5 -0
- package/.server/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +13 -0
- package/.server/server/plugins/engine/views/components/osgridreffield.html +13 -0
- package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
- package/package.json +3 -3
- package/src/client/stylesheets/_location-input.scss +60 -0
- package/src/client/stylesheets/application.scss +1 -6
- package/src/client/stylesheets/shared.scss +8 -0
- package/src/server/forms/register-as-a-unicorn-breeder.yaml +28 -0
- package/src/server/plugins/engine/components/ComponentBase.ts +1 -1
- package/src/server/plugins/engine/components/EastingNorthingField.test.ts +665 -0
- package/src/server/plugins/engine/components/EastingNorthingField.ts +224 -0
- package/src/server/plugins/engine/components/LatLongField.test.ts +700 -0
- package/src/server/plugins/engine/components/LatLongField.ts +213 -0
- package/src/server/plugins/engine/components/LocationFieldBase.test.ts +253 -0
- package/src/server/plugins/engine/components/LocationFieldBase.ts +152 -0
- package/src/server/plugins/engine/components/LocationFieldHelpers.test.ts +338 -0
- package/src/server/plugins/engine/components/LocationFieldHelpers.ts +123 -0
- package/src/server/plugins/engine/components/NationalGridFieldNumberField.test.ts +438 -0
- package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +52 -0
- package/src/server/plugins/engine/components/OsGridRefField.test.ts +469 -0
- package/src/server/plugins/engine/components/OsGridRefField.ts +71 -0
- package/src/server/plugins/engine/components/helpers/components.test.ts +270 -0
- package/src/server/plugins/engine/components/helpers/components.ts +39 -47
- package/src/server/plugins/engine/components/helpers/helpers.test.ts +71 -1
- package/src/server/plugins/engine/components/index.ts +4 -0
- package/src/server/plugins/engine/components/markdownParser.ts +40 -0
- package/src/server/plugins/engine/components/types.ts +14 -0
- package/src/server/plugins/engine/outputFormatters/adapter/v1.location.test.ts +356 -0
- package/src/server/plugins/engine/pageControllers/helpers/helpers.test.ts +4 -0
- package/src/server/plugins/engine/pageControllers/helpers/pages.ts +8 -0
- package/src/server/plugins/engine/types/index.ts +2 -0
- package/src/server/plugins/engine/types.ts +4 -0
- package/src/server/plugins/engine/views/components/_location-field-base.html +53 -0
- package/src/server/plugins/engine/views/components/eastingnorthingfield.html +5 -0
- package/src/server/plugins/engine/views/components/latlongfield.html +5 -0
- package/src/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +13 -0
- package/src/server/plugins/engine/views/components/osgridreffield.html +13 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { ComponentType, type LatLongFieldComponent } from '@defra/forms-model'
|
|
2
|
+
|
|
3
|
+
import { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'
|
|
4
|
+
import { type LatLongField } from '~/src/server/plugins/engine/components/LatLongField.js'
|
|
5
|
+
import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
|
|
6
|
+
import definition from '~/test/form/definitions/blank.js'
|
|
7
|
+
|
|
8
|
+
describe('LocationFieldHelpers', () => {
|
|
9
|
+
let model: FormModel
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
model = new FormModel(definition, {
|
|
13
|
+
basePath: 'test'
|
|
14
|
+
})
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
describe('getLocationFieldViewModel', () => {
|
|
18
|
+
it('should return view model with fieldset', () => {
|
|
19
|
+
const def: LatLongFieldComponent = {
|
|
20
|
+
title: 'Example lat long',
|
|
21
|
+
name: 'myComponent',
|
|
22
|
+
type: ComponentType.LatLongField,
|
|
23
|
+
options: {},
|
|
24
|
+
schema: {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const collection = new ComponentCollection([def], { model })
|
|
28
|
+
const field = collection.fields[0] as LatLongField
|
|
29
|
+
|
|
30
|
+
const payload = {
|
|
31
|
+
myComponent__latitude: 51.5,
|
|
32
|
+
myComponent__longitude: -0.1
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const viewModel = field.getViewModel(payload)
|
|
36
|
+
|
|
37
|
+
expect(viewModel.fieldset).toEqual({
|
|
38
|
+
legend: {
|
|
39
|
+
text: def.title,
|
|
40
|
+
classes: 'govuk-fieldset__legend--m'
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
expect(viewModel.items).toHaveLength(2)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('should include instruction text in view model when provided', () => {
|
|
48
|
+
const def: LatLongFieldComponent = {
|
|
49
|
+
title: 'Example lat long',
|
|
50
|
+
name: 'myComponent',
|
|
51
|
+
type: ComponentType.LatLongField,
|
|
52
|
+
options: {
|
|
53
|
+
instructionText: 'Enter coordinates in decimal format'
|
|
54
|
+
},
|
|
55
|
+
schema: {}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const collection = new ComponentCollection([def], { model })
|
|
59
|
+
const field = collection.fields[0] as LatLongField
|
|
60
|
+
|
|
61
|
+
const payload = {
|
|
62
|
+
myComponent__latitude: 51.5,
|
|
63
|
+
myComponent__longitude: -0.1
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const viewModel = field.getViewModel(payload)
|
|
67
|
+
|
|
68
|
+
const instructionText =
|
|
69
|
+
'instructionText' in viewModel ? viewModel.instructionText : undefined
|
|
70
|
+
expect(instructionText).toBeTruthy()
|
|
71
|
+
expect(instructionText).toContain('decimal format')
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('should add error classes to items when component has errors', () => {
|
|
75
|
+
const def: LatLongFieldComponent = {
|
|
76
|
+
title: 'Example lat long',
|
|
77
|
+
name: 'myComponent',
|
|
78
|
+
type: ComponentType.LatLongField,
|
|
79
|
+
options: {},
|
|
80
|
+
schema: {}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const collection = new ComponentCollection([def], { model })
|
|
84
|
+
const field = collection.fields[0] as LatLongField
|
|
85
|
+
|
|
86
|
+
const payload = {
|
|
87
|
+
myComponent__latitude: '',
|
|
88
|
+
myComponent__longitude: ''
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const errors = [
|
|
92
|
+
{
|
|
93
|
+
name: 'myComponent',
|
|
94
|
+
text: 'Error message',
|
|
95
|
+
path: ['myComponent'],
|
|
96
|
+
href: '#myComponent'
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
const viewModel = field.getViewModel(payload, errors)
|
|
101
|
+
|
|
102
|
+
expect(viewModel.items[0]).toEqual(
|
|
103
|
+
expect.objectContaining({
|
|
104
|
+
classes: expect.stringContaining('govuk-input--error')
|
|
105
|
+
})
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
expect(viewModel.items[1]).toEqual(
|
|
109
|
+
expect.objectContaining({
|
|
110
|
+
classes: expect.stringContaining('govuk-input--error')
|
|
111
|
+
})
|
|
112
|
+
)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('should add error classes to items when subfield has errors', () => {
|
|
116
|
+
const def: LatLongFieldComponent = {
|
|
117
|
+
title: 'Example lat long',
|
|
118
|
+
name: 'myComponent',
|
|
119
|
+
type: ComponentType.LatLongField,
|
|
120
|
+
options: {},
|
|
121
|
+
schema: {}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const collection = new ComponentCollection([def], { model })
|
|
125
|
+
const field = collection.fields[0] as LatLongField
|
|
126
|
+
|
|
127
|
+
const payload = {
|
|
128
|
+
myComponent__latitude: 'invalid',
|
|
129
|
+
myComponent__longitude: '-0.1'
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const errors = [
|
|
133
|
+
{
|
|
134
|
+
name: 'myComponent__latitude',
|
|
135
|
+
text: 'Invalid latitude',
|
|
136
|
+
path: ['myComponent__latitude'],
|
|
137
|
+
href: '#myComponent__latitude'
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
const viewModel = field.getViewModel(payload, errors)
|
|
142
|
+
|
|
143
|
+
expect(viewModel.items[0]).toEqual(
|
|
144
|
+
expect.objectContaining({
|
|
145
|
+
classes: expect.stringContaining('govuk-input--error')
|
|
146
|
+
})
|
|
147
|
+
)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('should handle labels correctly in view model items', () => {
|
|
151
|
+
const def: LatLongFieldComponent = {
|
|
152
|
+
title: 'Example lat long',
|
|
153
|
+
name: 'myComponent',
|
|
154
|
+
type: ComponentType.LatLongField,
|
|
155
|
+
options: {},
|
|
156
|
+
schema: {}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const collection = new ComponentCollection([def], { model })
|
|
160
|
+
const field = collection.fields[0] as LatLongField
|
|
161
|
+
|
|
162
|
+
const payload = {
|
|
163
|
+
myComponent__latitude: '51.5',
|
|
164
|
+
myComponent__longitude: '-0.1'
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const viewModel = field.getViewModel(payload)
|
|
168
|
+
|
|
169
|
+
const label = viewModel.items[0].label
|
|
170
|
+
expect(label).toBeDefined()
|
|
171
|
+
expect(label?.text).toBe('Latitude')
|
|
172
|
+
|
|
173
|
+
const labelString =
|
|
174
|
+
label && 'toString' in label && typeof label.toString === 'function'
|
|
175
|
+
? (label as { toString: () => string }).toString()
|
|
176
|
+
: ''
|
|
177
|
+
expect(labelString).toBe('Latitude')
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('should use existing fieldset if provided', () => {
|
|
181
|
+
const def: LatLongFieldComponent = {
|
|
182
|
+
title: 'Example lat long',
|
|
183
|
+
name: 'myComponent',
|
|
184
|
+
type: ComponentType.LatLongField,
|
|
185
|
+
options: {},
|
|
186
|
+
schema: {}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const collection = new ComponentCollection([def], { model })
|
|
190
|
+
const field = collection.fields[0] as LatLongField
|
|
191
|
+
|
|
192
|
+
const payload = {
|
|
193
|
+
myComponent__latitude: 51.5,
|
|
194
|
+
myComponent__longitude: -0.1
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const viewModel = field.getViewModel(payload)
|
|
198
|
+
|
|
199
|
+
expect(viewModel.fieldset).toBeDefined()
|
|
200
|
+
})
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
describe('createLocationFieldValidator', () => {
|
|
204
|
+
it('should return error when required field is empty', () => {
|
|
205
|
+
const def: LatLongFieldComponent = {
|
|
206
|
+
title: 'Example lat long',
|
|
207
|
+
name: 'myComponent',
|
|
208
|
+
type: ComponentType.LatLongField,
|
|
209
|
+
options: {},
|
|
210
|
+
schema: {}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const collection = new ComponentCollection([def], { model })
|
|
214
|
+
|
|
215
|
+
const payload = {
|
|
216
|
+
myComponent__latitude: '',
|
|
217
|
+
myComponent__longitude: ''
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const result = collection.validate(payload)
|
|
221
|
+
|
|
222
|
+
expect(result.errors).toBeTruthy()
|
|
223
|
+
expect(result.errors?.length).toBeGreaterThan(0)
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('should return error when required field has invalid state', () => {
|
|
227
|
+
const def: LatLongFieldComponent = {
|
|
228
|
+
title: 'Example lat long',
|
|
229
|
+
name: 'myComponent',
|
|
230
|
+
type: ComponentType.LatLongField,
|
|
231
|
+
options: {
|
|
232
|
+
required: true
|
|
233
|
+
},
|
|
234
|
+
schema: {}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const collection = new ComponentCollection([def], { model })
|
|
238
|
+
|
|
239
|
+
const payload = {
|
|
240
|
+
myComponent__latitude: 'not_a_number',
|
|
241
|
+
myComponent__longitude: 'also_not_a_number'
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const result = collection.validate(payload)
|
|
245
|
+
|
|
246
|
+
expect(result.errors).toBeTruthy()
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it('should not return error when optional field is empty', () => {
|
|
250
|
+
const def: LatLongFieldComponent = {
|
|
251
|
+
title: 'Example lat long',
|
|
252
|
+
name: 'myComponent',
|
|
253
|
+
type: ComponentType.LatLongField,
|
|
254
|
+
options: {
|
|
255
|
+
required: false
|
|
256
|
+
},
|
|
257
|
+
schema: {}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const collection = new ComponentCollection([def], { model })
|
|
261
|
+
|
|
262
|
+
const payload = {
|
|
263
|
+
myComponent__latitude: '',
|
|
264
|
+
myComponent__longitude: ''
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const result = collection.validate(payload)
|
|
268
|
+
|
|
269
|
+
expect(result.errors).toBeUndefined()
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
it('should return error when required field is partially filled', () => {
|
|
273
|
+
const def: LatLongFieldComponent = {
|
|
274
|
+
title: 'Example lat long',
|
|
275
|
+
name: 'myComponent',
|
|
276
|
+
type: ComponentType.LatLongField,
|
|
277
|
+
options: {},
|
|
278
|
+
schema: {}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const collection = new ComponentCollection([def], { model })
|
|
282
|
+
|
|
283
|
+
const payload = {
|
|
284
|
+
myComponent__latitude: '51.5',
|
|
285
|
+
myComponent__longitude: ''
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const result = collection.validate(payload)
|
|
289
|
+
|
|
290
|
+
expect(result.errors).toBeTruthy()
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it('should not return error when all required fields are filled', () => {
|
|
294
|
+
const def: LatLongFieldComponent = {
|
|
295
|
+
title: 'Example lat long',
|
|
296
|
+
name: 'myComponent',
|
|
297
|
+
type: ComponentType.LatLongField,
|
|
298
|
+
options: {},
|
|
299
|
+
schema: {}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const collection = new ComponentCollection([def], { model })
|
|
303
|
+
|
|
304
|
+
const payload = {
|
|
305
|
+
myComponent__latitude: '51.5',
|
|
306
|
+
myComponent__longitude: '-0.1'
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const result = collection.validate(payload)
|
|
310
|
+
|
|
311
|
+
expect(result.errors).toBeUndefined()
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
it('should validate optional fields correctly when partially filled', () => {
|
|
315
|
+
const def: LatLongFieldComponent = {
|
|
316
|
+
title: 'Example lat long',
|
|
317
|
+
name: 'myComponent',
|
|
318
|
+
type: ComponentType.LatLongField,
|
|
319
|
+
options: {
|
|
320
|
+
required: false
|
|
321
|
+
},
|
|
322
|
+
schema: {}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const collection = new ComponentCollection([def], { model })
|
|
326
|
+
|
|
327
|
+
const payload = {
|
|
328
|
+
myComponent__latitude: '51.5',
|
|
329
|
+
myComponent__longitude: ''
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const result = collection.validate(payload)
|
|
333
|
+
|
|
334
|
+
expect(result.errors).toBeTruthy()
|
|
335
|
+
expect(result.errors?.length).toBeGreaterThan(0)
|
|
336
|
+
})
|
|
337
|
+
})
|
|
338
|
+
})
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { type Context, type CustomValidator } from 'joi'
|
|
2
|
+
|
|
3
|
+
import { type EastingNorthingField } from '~/src/server/plugins/engine/components/EastingNorthingField.js'
|
|
4
|
+
import { isFormValue } from '~/src/server/plugins/engine/components/FormComponent.js'
|
|
5
|
+
import { type LatLongField } from '~/src/server/plugins/engine/components/LatLongField.js'
|
|
6
|
+
import { markdown } from '~/src/server/plugins/engine/components/markdownParser.js'
|
|
7
|
+
import {
|
|
8
|
+
type DateInputItem,
|
|
9
|
+
type Label,
|
|
10
|
+
type ViewModel
|
|
11
|
+
} from '~/src/server/plugins/engine/components/types.js'
|
|
12
|
+
import {
|
|
13
|
+
type FormPayload,
|
|
14
|
+
type FormSubmissionError,
|
|
15
|
+
type FormValue
|
|
16
|
+
} from '~/src/server/plugins/engine/types.js'
|
|
17
|
+
|
|
18
|
+
export type LocationField =
|
|
19
|
+
| InstanceType<typeof EastingNorthingField>
|
|
20
|
+
| InstanceType<typeof LatLongField>
|
|
21
|
+
|
|
22
|
+
export function getLocationFieldViewModel(
|
|
23
|
+
component: LocationField,
|
|
24
|
+
viewModel: ViewModel & {
|
|
25
|
+
label: Label
|
|
26
|
+
id: string
|
|
27
|
+
name: string
|
|
28
|
+
value: FormValue
|
|
29
|
+
},
|
|
30
|
+
payload: FormPayload,
|
|
31
|
+
errors?: FormSubmissionError[]
|
|
32
|
+
) {
|
|
33
|
+
const { collection, name } = component
|
|
34
|
+
const { fieldset: existingFieldset, label } = viewModel
|
|
35
|
+
|
|
36
|
+
// Check for component errors only
|
|
37
|
+
const hasError = errors?.some((error) => error.name === name)
|
|
38
|
+
|
|
39
|
+
// Use the component collection to generate the subitems
|
|
40
|
+
const items: DateInputItem[] = collection
|
|
41
|
+
.getViewModel(payload, errors)
|
|
42
|
+
.map(({ model }): DateInputItem => {
|
|
43
|
+
let { label, type, value, classes, prefix, suffix, errorMessage } = model
|
|
44
|
+
|
|
45
|
+
if (label) {
|
|
46
|
+
label.toString = () => label.text // Use string labels
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (hasError || errorMessage) {
|
|
50
|
+
classes = `${classes ?? ''} govuk-input--error`.trim()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Allow any `toString()`-able value so non-numeric
|
|
54
|
+
// values are shown alongside their error messages
|
|
55
|
+
if (!isFormValue(value)) {
|
|
56
|
+
value = undefined
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
label,
|
|
61
|
+
id: model.id,
|
|
62
|
+
name: model.name,
|
|
63
|
+
type,
|
|
64
|
+
value,
|
|
65
|
+
classes,
|
|
66
|
+
prefix,
|
|
67
|
+
suffix
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const fieldset = existingFieldset ?? {
|
|
72
|
+
legend: {
|
|
73
|
+
text: label.text,
|
|
74
|
+
classes: 'govuk-fieldset__legend--m'
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const result = {
|
|
79
|
+
...viewModel,
|
|
80
|
+
fieldset,
|
|
81
|
+
items
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (component.options.instructionText) {
|
|
85
|
+
return {
|
|
86
|
+
...result,
|
|
87
|
+
instructionText: markdown.parse(component.options.instructionText, {
|
|
88
|
+
async: false
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return result
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Validator factory for location-based fields.
|
|
98
|
+
* This creates a validator that ensures all required fields are present.
|
|
99
|
+
*/
|
|
100
|
+
export function createLocationFieldValidator(
|
|
101
|
+
component: LocationField
|
|
102
|
+
): CustomValidator {
|
|
103
|
+
return (payload: FormPayload, helpers) => {
|
|
104
|
+
const { collection, name, options } = component
|
|
105
|
+
|
|
106
|
+
const values = component.getFormValueFromState(
|
|
107
|
+
component.getStateFromValidForm(payload)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
const context: Context = {
|
|
111
|
+
missing: collection.keys,
|
|
112
|
+
key: name
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!component.isState(values)) {
|
|
116
|
+
return options.required !== false
|
|
117
|
+
? helpers.error('object.required', context)
|
|
118
|
+
: payload
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return payload
|
|
122
|
+
}
|
|
123
|
+
}
|