@defra/forms-model 3.0.447 → 3.0.449

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.
Files changed (95) hide show
  1. package/dist/module/form/form-definition/index.js +1 -1
  2. package/dist/module/form/form-definition/index.js.map +1 -1
  3. package/dist/module/form/form-editor/__stubs__/preview.js +105 -0
  4. package/dist/module/form/form-editor/__stubs__/preview.js.map +1 -0
  5. package/dist/module/form/form-editor/index.js +14 -0
  6. package/dist/module/form/form-editor/index.js.map +1 -1
  7. package/dist/module/form/form-editor/preview/date-input.js +17 -0
  8. package/dist/module/form/form-editor/preview/date-input.js.map +1 -0
  9. package/dist/module/form/form-editor/preview/email-address.js +6 -0
  10. package/dist/module/form/form-editor/preview/email-address.js.map +1 -0
  11. package/dist/module/form/form-editor/preview/index.js +11 -0
  12. package/dist/module/form/form-editor/preview/index.js.map +1 -0
  13. package/dist/module/form/form-editor/preview/list-sortable.js +40 -0
  14. package/dist/module/form/form-editor/preview/list-sortable.js.map +1 -0
  15. package/dist/module/form/form-editor/preview/list.js +182 -0
  16. package/dist/module/form/form-editor/preview/list.js.map +1 -0
  17. package/dist/module/form/form-editor/preview/phone-number.js +10 -0
  18. package/dist/module/form/form-editor/preview/phone-number.js.map +1 -0
  19. package/dist/module/form/form-editor/preview/question.js +197 -0
  20. package/dist/module/form/form-editor/preview/question.js.map +1 -0
  21. package/dist/module/form/form-editor/preview/radio-sortable.js +5 -0
  22. package/dist/module/form/form-editor/preview/radio-sortable.js.map +1 -0
  23. package/dist/module/form/form-editor/preview/radio.js +5 -0
  24. package/dist/module/form/form-editor/preview/radio.js.map +1 -0
  25. package/dist/module/form/form-editor/preview/short-answer.js +3 -0
  26. package/dist/module/form/form-editor/preview/short-answer.js.map +1 -0
  27. package/dist/module/form/form-editor/preview/types.js +2 -0
  28. package/dist/module/form/form-editor/preview/types.js.map +1 -0
  29. package/dist/module/form/form-editor/preview/uk-address.js +6 -0
  30. package/dist/module/form/form-editor/preview/uk-address.js.map +1 -0
  31. package/dist/module/form/form-editor/types.js.map +1 -1
  32. package/dist/module/form/form-manager/types.js.map +1 -1
  33. package/dist/module/index.js +1 -1
  34. package/dist/module/index.js.map +1 -1
  35. package/dist/types/form/form-definition/index.d.ts +2 -1
  36. package/dist/types/form/form-definition/index.d.ts.map +1 -1
  37. package/dist/types/form/form-editor/__stubs__/preview.d.ts +72 -0
  38. package/dist/types/form/form-editor/__stubs__/preview.d.ts.map +1 -0
  39. package/dist/types/form/form-editor/index.d.ts +7 -1
  40. package/dist/types/form/form-editor/index.d.ts.map +1 -1
  41. package/dist/types/form/form-editor/preview/date-input.d.ts +10 -0
  42. package/dist/types/form/form-editor/preview/date-input.d.ts.map +1 -0
  43. package/dist/types/form/form-editor/preview/email-address.d.ts +4 -0
  44. package/dist/types/form/form-editor/preview/email-address.d.ts.map +1 -0
  45. package/dist/types/form/form-editor/preview/index.d.ts +11 -0
  46. package/dist/types/form/form-editor/preview/index.d.ts.map +1 -0
  47. package/dist/types/form/form-editor/preview/list-sortable.d.ts +17 -0
  48. package/dist/types/form/form-editor/preview/list-sortable.d.ts.map +1 -0
  49. package/dist/types/form/form-editor/preview/list.d.ts +81 -0
  50. package/dist/types/form/form-editor/preview/list.d.ts.map +1 -0
  51. package/dist/types/form/form-editor/preview/phone-number.d.ts +4 -0
  52. package/dist/types/form/form-editor/preview/phone-number.d.ts.map +1 -0
  53. package/dist/types/form/form-editor/preview/question.d.ts +119 -0
  54. package/dist/types/form/form-editor/preview/question.d.ts.map +1 -0
  55. package/dist/types/form/form-editor/preview/radio-sortable.d.ts +4 -0
  56. package/dist/types/form/form-editor/preview/radio-sortable.d.ts.map +1 -0
  57. package/dist/types/form/form-editor/preview/radio.d.ts +4 -0
  58. package/dist/types/form/form-editor/preview/radio.d.ts.map +1 -0
  59. package/dist/types/form/form-editor/preview/short-answer.d.ts +4 -0
  60. package/dist/types/form/form-editor/preview/short-answer.d.ts.map +1 -0
  61. package/dist/types/form/form-editor/preview/types.d.ts +52 -0
  62. package/dist/types/form/form-editor/preview/types.d.ts.map +1 -0
  63. package/dist/types/form/form-editor/preview/uk-address.d.ts +4 -0
  64. package/dist/types/form/form-editor/preview/uk-address.d.ts.map +1 -0
  65. package/dist/types/form/form-editor/types.d.ts +36 -6
  66. package/dist/types/form/form-editor/types.d.ts.map +1 -1
  67. package/dist/types/form/form-manager/types.d.ts +2 -2
  68. package/dist/types/form/form-manager/types.d.ts.map +1 -1
  69. package/dist/types/index.d.ts +2 -1
  70. package/dist/types/index.d.ts.map +1 -1
  71. package/package.json +2 -2
  72. package/src/form/form-definition/index.ts +1 -1
  73. package/src/form/form-editor/__stubs__/preview.js +101 -0
  74. package/src/form/form-editor/index.ts +43 -1
  75. package/src/form/form-editor/preview/date-input.js +18 -0
  76. package/src/form/form-editor/preview/email-address.js +6 -0
  77. package/src/form/form-editor/preview/index.js +10 -0
  78. package/src/form/form-editor/preview/list-sortable.js +39 -0
  79. package/src/form/form-editor/preview/list.js +202 -0
  80. package/src/form/form-editor/preview/phone-number.js +10 -0
  81. package/src/form/form-editor/preview/question.js +199 -0
  82. package/src/form/form-editor/preview/radio-sortable.js +5 -0
  83. package/src/form/form-editor/preview/radio.js +5 -0
  84. package/src/form/form-editor/preview/short-answer.js +3 -0
  85. package/src/form/form-editor/preview/types.ts +60 -0
  86. package/src/form/form-editor/preview/uk-address.js +6 -0
  87. package/src/form/form-editor/types.ts +47 -2
  88. package/src/form/form-manager/types.ts +2 -2
  89. package/src/index.ts +2 -1
  90. package/dist/module/form/form-manager/index.js +0 -7
  91. package/dist/module/form/form-manager/index.js.map +0 -1
  92. package/dist/types/form/form-manager/index.d.ts +0 -3
  93. package/dist/types/form/form-manager/index.d.ts.map +0 -1
  94. package/schemas/patch-page-schema.json +0 -26
  95. package/src/form/form-manager/index.ts +0 -21
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,qCAAqC,CAAA;AACnD,cAAc,qCAAqC,CAAA;AACnD,cAAc,mCAAmC,CAAA;AACjD,cAAc,qCAAqC,CAAA;AACnD,cAAc,2BAA2B,CAAA;AACzC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,kCAAkC,CAAA;AAChD,cAAc,kCAAkC,CAAA;AAChD,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA;AACtC,cAAc,yBAAyB,CAAA;AAEvC,mBAAmB,uBAAuB,CAAA;AAC1C,mBAAmB,kCAAkC,CAAA;AACrD,mBAAmB,8BAA8B,CAAA;AACjD,mBAAmB,+BAA+B,CAAA;AAClD,mBAAmB,2BAA2B,CAAA;AAC9C,mBAAmB,2BAA2B,CAAA;AAC9C,mBAAmB,qCAAqC,CAAA;AACxD,mBAAmB,mCAAmC,CAAA;AACtD,mBAAmB,qCAAqC,CAAA;AACxD,mBAAmB,iCAAiC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,qCAAqC,CAAA;AACnD,cAAc,qCAAqC,CAAA;AACnD,cAAc,mCAAmC,CAAA;AACjD,cAAc,qCAAqC,CAAA;AACnD,cAAc,2BAA2B,CAAA;AACzC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yCAAyC,CAAA;AACvD,cAAc,kCAAkC,CAAA;AAChD,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA;AACtC,cAAc,yBAAyB,CAAA;AAEvC,mBAAmB,uBAAuB,CAAA;AAC1C,mBAAmB,kCAAkC,CAAA;AACrD,mBAAmB,8BAA8B,CAAA;AACjD,mBAAmB,+BAA+B,CAAA;AAClD,mBAAmB,2BAA2B,CAAA;AAC9C,mBAAmB,2BAA2B,CAAA;AAC9C,mBAAmB,qCAAqC,CAAA;AACxD,mBAAmB,mCAAmC,CAAA;AACtD,mBAAmB,qCAAqC,CAAA;AACxD,mBAAmB,yCAAyC,CAAA;AAC5D,mBAAmB,iCAAiC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra/forms-model",
3
- "version": "3.0.447",
3
+ "version": "3.0.449",
4
4
  "description": "A hapi plugin providing the model for Defra forms",
5
5
  "homepage": "https://github.com/DEFRA/forms-designer/tree/main/model#readme",
6
6
  "repository": {
@@ -15,7 +15,7 @@
15
15
  "types": "dist/types/index.d.ts",
16
16
  "scripts": {
17
17
  "build": "npm run build:types && npm run build:node && npm run build:schemas",
18
- "build:node": "babel --delete-dir-on-start --extensions \".ts\" --ignore \"**/*.test.*\" --copy-files --no-copy-ignored --source-maps --out-dir ./dist/module ./src",
18
+ "build:node": "babel --delete-dir-on-start --extensions \".ts,.js\" --ignore \"**/*.test.*\" --copy-files --no-copy-ignored --source-maps --out-dir ./dist/module ./src",
19
19
  "build:types": "tsc --build --force tsconfig.build.json && tsc-alias --project tsconfig.build.json",
20
20
  "build:schemas": "node scripts/generate-schemas.js",
21
21
  "test": "jest --color --coverage --verbose",
@@ -361,7 +361,7 @@ const repeatSchema = Joi.object<RepeatSchema>()
361
361
  .description('Maximum number of repetitions allowed')
362
362
  })
363
363
 
364
- const pageRepeatSchema = Joi.object<Repeat>()
364
+ export const pageRepeatSchema = Joi.object<Repeat>()
365
365
  .description('Complete configuration for a repeatable page')
366
366
  .keys({
367
367
  options: repeatOptions
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @implements {QuestionRenderer}
3
+ */
4
+ export class QuestionRendererStub {
5
+ /**
6
+ * @type {jest.Mock<void, [string, QuestionBaseModel]>}
7
+ */
8
+ renderMock
9
+
10
+ /**
11
+ * @param {jest.Mock<void, [string, QuestionBaseModel]>} renderMock
12
+ */
13
+ constructor(renderMock) {
14
+ this.renderMock = renderMock
15
+ }
16
+
17
+ /**
18
+ * @param {string} questionTemplate
19
+ * @param {QuestionBaseModel} questionBaseModel
20
+ */
21
+ render(questionTemplate, questionBaseModel) {
22
+ this.renderMock(questionTemplate, questionBaseModel)
23
+ }
24
+
25
+ /**
26
+ * @returns {string}
27
+ * @param {string} _questionTemplate
28
+ * @param {RenderContext} _renderContext
29
+ */
30
+ static buildHTML(_questionTemplate, _renderContext) {
31
+ return '**** BUILT HTML ****'
32
+ }
33
+ }
34
+
35
+ /**
36
+ * @implements {ListElements}
37
+ */
38
+ export class QuestionPreviewElements {
39
+ /**
40
+ * @protected
41
+ */
42
+ _question = ''
43
+ /** @protected */
44
+ _hintText = ''
45
+ /** @protected */
46
+ _optional = false
47
+ /**
48
+ * @type {string}
49
+ * @protected
50
+ */
51
+ _shortDesc = ''
52
+ /**
53
+ *
54
+ * @type {ListElement[]}
55
+ * @private
56
+ */
57
+ _items = []
58
+
59
+ afterInputsHTML = '<div class="govuk-inset-text">No items added yet.</div>'
60
+
61
+ /**
62
+ * @param {BaseSettings} baseSettings
63
+ */
64
+ constructor({ question, hintText, optional, shortDesc, items }) {
65
+ this._question = question
66
+ this._hintText = hintText
67
+ this._optional = optional
68
+ this._shortDesc = shortDesc
69
+ this._items = items
70
+ }
71
+
72
+ get values() {
73
+ return {
74
+ question: this._question,
75
+ hintText: this._hintText,
76
+ optional: this._optional,
77
+ shortDesc: this._shortDesc,
78
+ items: this._items
79
+ }
80
+ }
81
+
82
+ /**
83
+ * @param {string} _value
84
+ */
85
+ setPreviewHTML(_value) {
86
+ // Not implemented for server side render
87
+ }
88
+ }
89
+
90
+ export const baseElements = /** @type {BaseSettings} */ ({
91
+ items: [],
92
+ optional: false,
93
+ question: 'Which quest would you like to pick?',
94
+ hintText: 'Choose one adventure that best suits you.',
95
+ shortDesc: ''
96
+ })
97
+
98
+ /**
99
+ * @import { ListElement } from '~/src/form/form-editor/types.js'
100
+ * @import { BaseSettings, ListElements, RenderContext, QuestionBaseModel, QuestionElements, QuestionRenderer } from '~/src/form/form-editor/preview/types.js'
101
+ */
@@ -5,7 +5,10 @@ import {
5
5
  type FormEditorInputCheckAnswersSettings,
6
6
  type FormEditorInputPage,
7
7
  type FormEditorInputPageSettings,
8
- type FormEditorInputQuestion
8
+ type FormEditorInputQuestion,
9
+ type GovukField,
10
+ type GovukFieldQuestionOptional,
11
+ type GovukStringField
9
12
  } from '~/src/form/form-editor/types.js'
10
13
 
11
14
  export enum QuestionTypeSubGroup {
@@ -227,6 +230,27 @@ export const guidanceTextSchema = Joi.string()
227
230
  .trim()
228
231
  .description('Guidance text to assist users in completing the page')
229
232
 
233
+ export const repeaterSchema = Joi.string()
234
+ .trim()
235
+ .optional()
236
+ .description(
237
+ 'Combined min/max items and question set name for the repeater page'
238
+ )
239
+
240
+ export const minItemsSchema = Joi.number()
241
+ .empty('')
242
+ .min(1)
243
+ .description('The minimum number of repeater items')
244
+
245
+ export const maxItemsSchema = Joi.number()
246
+ .empty('')
247
+ .max(25)
248
+ .description('The maximum number of repeater items')
249
+
250
+ export const questionSetNameSchema = Joi.string()
251
+ .trim()
252
+ .description('The repeater question set name')
253
+
230
254
  export const needDeclarationSchema = Joi.string()
231
255
  .trim()
232
256
  .required()
@@ -559,3 +583,21 @@ export const formEditorInputPageSettingsSchema =
559
583
  .keys(formEditorInputPageSettingsKeys)
560
584
  .required()
561
585
  .description('Settings for page content and display in the form editor')
586
+
587
+ export function govukFieldValueIsString(
588
+ govukField: GovukField
589
+ ): govukField is GovukStringField {
590
+ return ['question', 'hintText', 'shortDescription'].includes(
591
+ `${govukField.name}`
592
+ )
593
+ }
594
+
595
+ export function govukFieldIsQuestionOptional(
596
+ govukField: GovukField
597
+ ): govukField is GovukFieldQuestionOptional {
598
+ if (govukField.name !== 'questionOptional') {
599
+ return false
600
+ }
601
+ const checkedValue = govukField.items?.[0].checked
602
+ return typeof checkedValue === 'boolean'
603
+ }
@@ -0,0 +1,18 @@
1
+ import { Question } from '~/src/form/form-editor/preview/question.js'
2
+
3
+ export class DateInputQuestion extends Question {
4
+ /**
5
+ * @type {string}
6
+ * @protected
7
+ */
8
+ _questionTemplate = 'date-input.njk'
9
+
10
+ get renderInput() {
11
+ return {
12
+ id: 'dateInput',
13
+ name: 'dateInputField',
14
+ fieldset: this.fieldSet,
15
+ hint: this.hint
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,6 @@
1
+ import { Question } from '~/src/form/form-editor/preview/question.js'
2
+
3
+ export class EmailAddressQuestion extends Question {
4
+ _questionTemplate = 'emailaddressfield.njk'
5
+ _fieldName = 'emailAddressField'
6
+ }
@@ -0,0 +1,10 @@
1
+ export * from '~/src/form/form-editor/preview/date-input.js'
2
+ export * from '~/src/form/form-editor/preview/email-address.js'
3
+ export * from '~/src/form/form-editor/preview/list.js'
4
+ export * from '~/src/form/form-editor/preview/list-sortable.js'
5
+ export * from '~/src/form/form-editor/preview/phone-number.js'
6
+ export * from '~/src/form/form-editor/preview/question.js'
7
+ export * from '~/src/form/form-editor/preview/radio.js'
8
+ export * from '~/src/form/form-editor/preview/radio-sortable.js'
9
+ export * from '~/src/form/form-editor/preview/short-answer.js'
10
+ export * from '~/src/form/form-editor/preview/uk-address.js'
@@ -0,0 +1,39 @@
1
+ import { ListQuestion } from '~/src/form/form-editor/preview/list.js'
2
+
3
+ export class ListSortableQuestion extends ListQuestion {
4
+ /**
5
+ * @param {ListElements} listElements
6
+ * @param {QuestionRenderer} questionRenderer
7
+ */
8
+ constructor(listElements, questionRenderer) {
9
+ super(listElements, questionRenderer)
10
+ const items = /** @type {ListElement[]} */ (listElements.values.items)
11
+ this._list = this.createListFromElements(items)
12
+ this._listElements = listElements
13
+ }
14
+
15
+ /**
16
+ * @returns {Map<string, ListElement>}
17
+ */
18
+ resyncPreviewAfterReorder() {
19
+ const newList = this._listElements.values.items
20
+ this._list = this.createListFromElements(newList)
21
+ this.render()
22
+ return this._list
23
+ }
24
+
25
+ get listElementObjects() {
26
+ return Array.from(this._list).map(([, value]) => ({
27
+ id: value.id,
28
+ text: value.text,
29
+ hint: value.hint?.text ? { text: value.hint.text } : undefined,
30
+ value: value.value
31
+ }))
32
+ }
33
+ }
34
+
35
+ /**
36
+ * @import {ListElement} from '~/src/form/form-editor/types.js'
37
+ * @import { QuestionRenderer, HTMLBuilder, ListElements, BaseSettings } from '~/src/form/form-editor/preview/types.js'
38
+ * @import { SortableEvent, SortableOptions } from 'sortablejs'
39
+ */
@@ -0,0 +1,202 @@
1
+ import { Question } from '~/src/form/form-editor/preview/question.js'
2
+
3
+ const DefaultListConst = {
4
+ TextElementId: 'radioText',
5
+ HintElementId: 'radioHint',
6
+ Template: 'radios.njk',
7
+ Input: 'listInput',
8
+ RenderName: 'listInputField'
9
+ }
10
+
11
+ /**
12
+ * @param {ListElement} listElement
13
+ * @returns {[string, ListElement]}
14
+ */
15
+ export function listItemMapper(listElement) {
16
+ return [listElement.id, listElement]
17
+ }
18
+
19
+ /**
20
+ *
21
+ * @param { ListElement[]| undefined } listElements
22
+ * @returns {Map<string, ListElement>}
23
+ */
24
+ export function listsElementToMap(listElements) {
25
+ const entries = listElements ? listElements.map(listItemMapper) : []
26
+ return new Map(entries)
27
+ }
28
+
29
+ export class ListQuestion extends Question {
30
+ /**
31
+ * @type {string}
32
+ * @protected
33
+ */
34
+ _questionTemplate = DefaultListConst.Template
35
+ /** @type {ListElements} */
36
+ _listElements
37
+ listRenderId = DefaultListConst.Input
38
+ listRenderName = DefaultListConst.RenderName
39
+
40
+ /**
41
+ * @type {Map<string, ListElement>}
42
+ * @protected
43
+ */
44
+ _list
45
+
46
+ /**
47
+ * @param {ListElements} listElements
48
+ * @param {QuestionRenderer} questionRenderer
49
+ */
50
+ constructor(listElements, questionRenderer) {
51
+ super(listElements, questionRenderer)
52
+
53
+ const items = /** @type {ListElement[]} */ (listElements.values.items)
54
+ this._list = this.createListFromElements(items)
55
+ this._listElements = listElements
56
+ }
57
+
58
+ get renderInput() {
59
+ const afterInputs =
60
+ /** @type {{ formGroup?: { afterInputs: { html: string } } }} */ (
61
+ this.list.length
62
+ ? {}
63
+ : {
64
+ formGroup: {
65
+ afterInputs: {
66
+ html: this._listElements.afterInputsHTML
67
+ }
68
+ }
69
+ }
70
+ )
71
+
72
+ return {
73
+ id: this.listRenderId,
74
+ name: this.listRenderName,
75
+ fieldset: this.fieldSet,
76
+ hint: this.hint,
77
+ items: this.list,
78
+ ...afterInputs
79
+ }
80
+ }
81
+
82
+ /**
83
+ *
84
+ * @param {ListElement} listElement
85
+ */
86
+ push(listElement) {
87
+ this._list.set(listElement.id, listElement)
88
+ this.render()
89
+ }
90
+
91
+ /**
92
+ * @param {string} key
93
+ */
94
+ delete(key) {
95
+ this._list.delete(key)
96
+ this.render()
97
+ }
98
+
99
+ /**
100
+ * @param {ListElement[]} listElements
101
+ * @returns {Map<string, ListElement>}
102
+ */
103
+ createListFromElements(listElements) {
104
+ this._list = listsElementToMap(listElements)
105
+ return this._list
106
+ }
107
+
108
+ /**
109
+ * @returns {ListItemReadonly[]}
110
+ * @readonly
111
+ */
112
+ get list() {
113
+ const iterator = /** @type {MapIterator<ListElement>} */ (
114
+ this._list.values()
115
+ )
116
+ return Array.from(iterator).map((listItem) => {
117
+ const hintText =
118
+ this._highlight === `${listItem.id}-hint` && !listItem.hint?.text.length
119
+ ? 'Hint text'
120
+ : (listItem.hint?.text ?? '')
121
+
122
+ const hint = {
123
+ hint: hintText
124
+ ? {
125
+ text: hintText,
126
+ classes: this.getHighlight(listItem.id + '-hint')
127
+ }
128
+ : undefined
129
+ }
130
+
131
+ const text = listItem.text.length ? listItem.text : 'Item text'
132
+
133
+ return {
134
+ ...listItem,
135
+ text,
136
+ ...hint,
137
+ label: {
138
+ text: listItem.text,
139
+ classes: this.getHighlight(listItem.id + '-label')
140
+ }
141
+ }
142
+ })
143
+ }
144
+
145
+ /**
146
+ *
147
+ * @param {string | undefined} id
148
+ * @param {string} text
149
+ */
150
+ updateText(id, text) {
151
+ if (!id) {
152
+ return
153
+ }
154
+
155
+ const listItem = this._list.get(id)
156
+ if (listItem) {
157
+ listItem.text = text
158
+ this.render()
159
+ }
160
+ }
161
+
162
+ /**
163
+ *
164
+ * @param {string | undefined} id
165
+ * @param {string} hint
166
+ */
167
+ updateHint(id, hint) {
168
+ if (!id) {
169
+ return
170
+ }
171
+
172
+ const listItem = this._list.get(id)
173
+ if (listItem) {
174
+ listItem.hint = {
175
+ ...listItem.hint,
176
+ text: hint
177
+ }
178
+ this.render()
179
+ }
180
+ }
181
+
182
+ /**
183
+ * @param {string | undefined} id
184
+ * @param {string} value
185
+ */
186
+ updateValue(id, value) {
187
+ if (!id) {
188
+ return
189
+ }
190
+
191
+ const listItem = this._list.get(id)
192
+ if (listItem) {
193
+ listItem.value = value
194
+ this.render()
195
+ }
196
+ }
197
+ }
198
+
199
+ /**
200
+ * @import { ListElement, ListItemReadonly } from '~/src/form/form-editor/types.js'
201
+ * @import { ListenerRow, ListElements, QuestionRenderer, HTMLBuilder } from '~/src/form/form-editor/preview/types.js'
202
+ */
@@ -0,0 +1,10 @@
1
+ import { Question } from '~/src/form/form-editor/preview/question.js'
2
+
3
+ export class PhoneNumberQuestion extends Question {
4
+ _questionTemplate = 'telephonenumberfield.njk'
5
+ _fieldName = 'phoneNumberField'
6
+ }
7
+
8
+ /**
9
+ * @import { QuestionBaseModel } from '~/src/form/form-editor/preview/question.js'
10
+ */
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @class Question
3
+ * @classdesc
4
+ * A data object that has access to the underlying data via the QuestionElements object interface
5
+ * and the templating mechanism to render the HTML for the data.
6
+ *
7
+ * It does not have access to the DOM, but has access to QuestionElements.setPreviewHTML to update
8
+ * the HTML. Question classes should only be responsible for data and rendering as are reused in the
9
+ * server side.
10
+ */
11
+ export class Question {
12
+ /**
13
+ * @type {string}
14
+ * @protected
15
+ */
16
+ _questionTemplate = 'textfield.njk'
17
+ /**
18
+ * @type { string|null }
19
+ * @protected
20
+ */
21
+ _highlight = null
22
+ /**
23
+ * @type {string}
24
+ * @protected
25
+ */
26
+ _fieldName = 'inputField'
27
+ /**
28
+ * @type {QuestionRenderer}
29
+ * @protected
30
+ */
31
+ _questionRenderer
32
+
33
+ /**
34
+ * @param {QuestionElements} htmlElements
35
+ * @param {QuestionRenderer} questionRenderer
36
+ */
37
+ constructor(htmlElements, questionRenderer) {
38
+ const { question, hintText, optional } = htmlElements.values
39
+
40
+ /**
41
+ * @type {QuestionElements}
42
+ * @private
43
+ */
44
+ this._htmlElements = htmlElements
45
+ /**
46
+ * @type {string}
47
+ * @private
48
+ */
49
+ this._question = question
50
+ /**
51
+ * @type {string}
52
+ * @private
53
+ */
54
+ this._hintText = hintText
55
+ /**
56
+ * @type {boolean}
57
+ * @private
58
+ */
59
+ this._optional = optional
60
+ /**
61
+ *
62
+ * @type {QuestionRenderer}
63
+ * @protected
64
+ */
65
+ this._questionRenderer = questionRenderer
66
+ }
67
+
68
+ /**
69
+ * @param {string} element
70
+ * @returns {string}
71
+ * @protected
72
+ */
73
+ getHighlight(element) {
74
+ return this._highlight === element ? ' highlight' : ''
75
+ }
76
+
77
+ get titleText() {
78
+ const optionalText = this._optional ? ' (optional)' : ''
79
+ return (!this._question ? 'Question' : this._question) + optionalText
80
+ }
81
+
82
+ /**
83
+ * @protected
84
+ * @type {DefaultComponent}
85
+ */
86
+ get label() {
87
+ return {
88
+ text: this.titleText,
89
+ classes: 'govuk-label--l' + this.getHighlight('question')
90
+ }
91
+ }
92
+
93
+ /**
94
+ * @protected
95
+ * @type {GovukFieldset}
96
+ */
97
+ get fieldSet() {
98
+ return {
99
+ legend: {
100
+ text: this.titleText,
101
+ classes: 'govuk-fieldset__legend--l' + this.getHighlight('question')
102
+ }
103
+ }
104
+ }
105
+
106
+ /**
107
+ * @type {DefaultComponent}
108
+ * @protected
109
+ */
110
+ get hint() {
111
+ const text =
112
+ this._highlight === 'hintText' && !this._hintText.length
113
+ ? 'Hint text'
114
+ : this._hintText
115
+
116
+ return {
117
+ text,
118
+ classes: this.getHighlight('hintText')
119
+ }
120
+ }
121
+
122
+ /**
123
+ * @type {QuestionBaseModel}
124
+ */
125
+ get renderInput() {
126
+ return {
127
+ id: this._fieldName,
128
+ name: this._fieldName,
129
+ label: this.label,
130
+ hint: this.hint
131
+ }
132
+ }
133
+
134
+ render() {
135
+ this._questionRenderer.render(this._questionTemplate, this.renderInput)
136
+ }
137
+
138
+ /**
139
+ * @type {string}
140
+ */
141
+ get question() {
142
+ return this._question
143
+ }
144
+
145
+ /**
146
+ * @param {string} value
147
+ */
148
+ set question(value) {
149
+ this._question = value
150
+ this.render()
151
+ }
152
+
153
+ /**
154
+ * @type {string}
155
+ */
156
+ get hintText() {
157
+ return this._hintText
158
+ }
159
+
160
+ /**
161
+ * @param {string} value
162
+ */
163
+ set hintText(value) {
164
+ this._hintText = value
165
+ this.render()
166
+ }
167
+
168
+ get optional() {
169
+ return this._optional
170
+ }
171
+
172
+ /**
173
+ * @param {boolean} value
174
+ */
175
+ set optional(value) {
176
+ this._optional = value
177
+ this.render()
178
+ }
179
+
180
+ /**
181
+ * @type {string | null}
182
+ */
183
+ get highlight() {
184
+ return this._highlight
185
+ }
186
+
187
+ /**
188
+ * @param {string | null} value
189
+ */
190
+ set highlight(value) {
191
+ this._highlight = value
192
+ this.render()
193
+ }
194
+ }
195
+
196
+ /**
197
+ * @import { ListenerRow, BaseSettings, QuestionElements, QuestionBaseModel, GovukFieldset, DefaultComponent, QuestionRenderer } from '~/src/form/form-editor/preview/types.js'
198
+ * @import { ListElement, ListItemReadonly } from '~/src/form/form-editor/types.js'
199
+ */
@@ -0,0 +1,5 @@
1
+ import { ListSortableQuestion } from '~/src/form/form-editor/preview/list-sortable.js'
2
+
3
+ export class RadioSortableQuestion extends ListSortableQuestion {
4
+ _questionTemplate = 'radios.njk'
5
+ }
@@ -0,0 +1,5 @@
1
+ import { ListQuestion } from '~/src/form/form-editor/preview/list.js'
2
+
3
+ export class RadioQuestion extends ListQuestion {
4
+ _questionTemplate = 'radios.njk'
5
+ }