@defra/forms-model 3.0.448 → 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 (80) hide show
  1. package/dist/module/form/form-editor/__stubs__/preview.js +105 -0
  2. package/dist/module/form/form-editor/__stubs__/preview.js.map +1 -0
  3. package/dist/module/form/form-editor/index.js +10 -0
  4. package/dist/module/form/form-editor/index.js.map +1 -1
  5. package/dist/module/form/form-editor/preview/date-input.js +17 -0
  6. package/dist/module/form/form-editor/preview/date-input.js.map +1 -0
  7. package/dist/module/form/form-editor/preview/email-address.js +6 -0
  8. package/dist/module/form/form-editor/preview/email-address.js.map +1 -0
  9. package/dist/module/form/form-editor/preview/index.js +11 -0
  10. package/dist/module/form/form-editor/preview/index.js.map +1 -0
  11. package/dist/module/form/form-editor/preview/list-sortable.js +40 -0
  12. package/dist/module/form/form-editor/preview/list-sortable.js.map +1 -0
  13. package/dist/module/form/form-editor/preview/list.js +182 -0
  14. package/dist/module/form/form-editor/preview/list.js.map +1 -0
  15. package/dist/module/form/form-editor/preview/phone-number.js +10 -0
  16. package/dist/module/form/form-editor/preview/phone-number.js.map +1 -0
  17. package/dist/module/form/form-editor/preview/question.js +197 -0
  18. package/dist/module/form/form-editor/preview/question.js.map +1 -0
  19. package/dist/module/form/form-editor/preview/radio-sortable.js +5 -0
  20. package/dist/module/form/form-editor/preview/radio-sortable.js.map +1 -0
  21. package/dist/module/form/form-editor/preview/radio.js +5 -0
  22. package/dist/module/form/form-editor/preview/radio.js.map +1 -0
  23. package/dist/module/form/form-editor/preview/short-answer.js +3 -0
  24. package/dist/module/form/form-editor/preview/short-answer.js.map +1 -0
  25. package/dist/module/form/form-editor/preview/types.js +2 -0
  26. package/dist/module/form/form-editor/preview/types.js.map +1 -0
  27. package/dist/module/form/form-editor/preview/uk-address.js +6 -0
  28. package/dist/module/form/form-editor/preview/uk-address.js.map +1 -0
  29. package/dist/module/form/form-editor/types.js.map +1 -1
  30. package/dist/module/index.js +1 -0
  31. package/dist/module/index.js.map +1 -1
  32. package/dist/types/form/form-editor/__stubs__/preview.d.ts +72 -0
  33. package/dist/types/form/form-editor/__stubs__/preview.d.ts.map +1 -0
  34. package/dist/types/form/form-editor/index.d.ts +3 -1
  35. package/dist/types/form/form-editor/index.d.ts.map +1 -1
  36. package/dist/types/form/form-editor/preview/date-input.d.ts +10 -0
  37. package/dist/types/form/form-editor/preview/date-input.d.ts.map +1 -0
  38. package/dist/types/form/form-editor/preview/email-address.d.ts +4 -0
  39. package/dist/types/form/form-editor/preview/email-address.d.ts.map +1 -0
  40. package/dist/types/form/form-editor/preview/index.d.ts +11 -0
  41. package/dist/types/form/form-editor/preview/index.d.ts.map +1 -0
  42. package/dist/types/form/form-editor/preview/list-sortable.d.ts +17 -0
  43. package/dist/types/form/form-editor/preview/list-sortable.d.ts.map +1 -0
  44. package/dist/types/form/form-editor/preview/list.d.ts +81 -0
  45. package/dist/types/form/form-editor/preview/list.d.ts.map +1 -0
  46. package/dist/types/form/form-editor/preview/phone-number.d.ts +4 -0
  47. package/dist/types/form/form-editor/preview/phone-number.d.ts.map +1 -0
  48. package/dist/types/form/form-editor/preview/question.d.ts +119 -0
  49. package/dist/types/form/form-editor/preview/question.d.ts.map +1 -0
  50. package/dist/types/form/form-editor/preview/radio-sortable.d.ts +4 -0
  51. package/dist/types/form/form-editor/preview/radio-sortable.d.ts.map +1 -0
  52. package/dist/types/form/form-editor/preview/radio.d.ts +4 -0
  53. package/dist/types/form/form-editor/preview/radio.d.ts.map +1 -0
  54. package/dist/types/form/form-editor/preview/short-answer.d.ts +4 -0
  55. package/dist/types/form/form-editor/preview/short-answer.d.ts.map +1 -0
  56. package/dist/types/form/form-editor/preview/types.d.ts +52 -0
  57. package/dist/types/form/form-editor/preview/types.d.ts.map +1 -0
  58. package/dist/types/form/form-editor/preview/uk-address.d.ts +4 -0
  59. package/dist/types/form/form-editor/preview/uk-address.d.ts.map +1 -0
  60. package/dist/types/form/form-editor/types.d.ts +19 -5
  61. package/dist/types/form/form-editor/types.d.ts.map +1 -1
  62. package/dist/types/index.d.ts +2 -0
  63. package/dist/types/index.d.ts.map +1 -1
  64. package/package.json +2 -2
  65. package/src/form/form-editor/__stubs__/preview.js +101 -0
  66. package/src/form/form-editor/index.ts +22 -1
  67. package/src/form/form-editor/preview/date-input.js +18 -0
  68. package/src/form/form-editor/preview/email-address.js +6 -0
  69. package/src/form/form-editor/preview/index.js +10 -0
  70. package/src/form/form-editor/preview/list-sortable.js +39 -0
  71. package/src/form/form-editor/preview/list.js +202 -0
  72. package/src/form/form-editor/preview/phone-number.js +10 -0
  73. package/src/form/form-editor/preview/question.js +199 -0
  74. package/src/form/form-editor/preview/radio-sortable.js +5 -0
  75. package/src/form/form-editor/preview/radio.js +5 -0
  76. package/src/form/form-editor/preview/short-answer.js +3 -0
  77. package/src/form/form-editor/preview/types.ts +60 -0
  78. package/src/form/form-editor/preview/uk-address.js +6 -0
  79. package/src/form/form-editor/types.ts +20 -1
  80. package/src/index.ts +2 -0
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ import { Question } from '~/src/form/form-editor/preview/question.js'
2
+
3
+ export class ShortAnswerQuestion extends Question {}
@@ -0,0 +1,60 @@
1
+ import {
2
+ type ListElement,
3
+ type ListItemReadonly
4
+ } from '~/src/form/form-editor/types.js'
5
+
6
+ export interface BaseSettings {
7
+ question: string
8
+ hintText: string
9
+ optional: boolean
10
+ shortDesc: string
11
+ items: ListElement[]
12
+ }
13
+
14
+ export interface DefaultComponent {
15
+ id?: string
16
+ text: string
17
+ classes: string
18
+ }
19
+
20
+ export interface GovukFieldset {
21
+ legend: DefaultComponent
22
+ }
23
+
24
+ export interface QuestionBaseModel {
25
+ id?: string
26
+ name?: string
27
+ label?: DefaultComponent
28
+ hint?: DefaultComponent
29
+ fieldset?: GovukFieldset
30
+ readonly items?: ListItemReadonly[]
31
+ text?: string
32
+ formGroup?: { afterInputs: { html: string } }
33
+ }
34
+
35
+ export type ListenerRow = [
36
+ HTMLInputElement | null,
37
+ (target: HTMLInputElement, e: Event) => void,
38
+ keyof HTMLElementEventMap
39
+ ]
40
+
41
+ export interface QuestionElements {
42
+ readonly values: BaseSettings
43
+ setPreviewHTML(value: string): void
44
+ }
45
+
46
+ export interface RenderContext {
47
+ model: QuestionBaseModel
48
+ }
49
+
50
+ export interface HTMLBuilder {
51
+ buildHTML(questionTemplate: string, renderContext: RenderContext): string
52
+ }
53
+
54
+ export interface QuestionRenderer {
55
+ render(questionTemplate: string, questionBaseModel: QuestionBaseModel): void
56
+ }
57
+
58
+ export interface ListElements extends QuestionElements {
59
+ afterInputsHTML: string
60
+ }
@@ -0,0 +1,6 @@
1
+ import { Question } from '~/src/form/form-editor/preview/question.js'
2
+
3
+ export class UkAddressQuestion extends Question {
4
+ _questionTemplate = 'ukaddressfield.njk'
5
+ _fieldName = 'addressField'
6
+ }
@@ -380,6 +380,12 @@ export interface QuestionSessionState {
380
380
  lastMoveDirection?: string
381
381
  }
382
382
 
383
+ export interface GovukFieldItem {
384
+ text?: string
385
+ value?: string
386
+ checked?: boolean
387
+ }
388
+
383
389
  export interface GovukField {
384
390
  id?: string
385
391
  name?: string
@@ -396,12 +402,25 @@ export interface GovukField {
396
402
  isPageHeading?: boolean
397
403
  }
398
404
  hint?: { text?: string; html?: string; classes?: string }
399
- items?: { text?: string; value?: string; checked?: boolean }[]
405
+ items?: GovukFieldItem[]
400
406
  rows?: number
401
407
  type?: string
402
408
  customTemplate?: string
403
409
  }
404
410
 
411
+ export type GovukFieldQuestionOptional = Omit<GovukField, 'name' | 'items'> & {
412
+ name: 'questionOptional'
413
+ items: [
414
+ {
415
+ text?: string
416
+ value?: string
417
+ checked: boolean
418
+ }
419
+ ]
420
+ }
421
+
422
+ export type GovukStringField = Omit<GovukField, 'value'> & { value: string }
423
+
405
424
  export interface FormEditorGovukField {
406
425
  question?: GovukField
407
426
  hintText?: GovukField
package/src/index.ts CHANGED
@@ -12,6 +12,7 @@ export * from '~/src/form/form-metadata/index.js'
12
12
  export * from '~/src/form/form-submission/index.js'
13
13
  export * from '~/src/form/utils/index.js'
14
14
  export * from '~/src/form/form-editor/index.js'
15
+ export * from '~/src/form/form-editor/preview/index.js'
15
16
  export * from '~/src/form/form-manager/types.js'
16
17
  export * from '~/src/pages/index.js'
17
18
  export * from '~/src/utils/helpers.js'
@@ -26,4 +27,5 @@ export type * from '~/src/conditions/types.js'
26
27
  export type * from '~/src/form/form-definition/types.js'
27
28
  export type * from '~/src/form/form-metadata/types.js'
28
29
  export type * from '~/src/form/form-submission/types.js'
30
+ export type * from '~/src/form/form-editor/preview/types.js'
29
31
  export type * from '~/src/form/form-editor/types.js'