govuk_publishing_components 58.1.1 → 58.2.0

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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/select-with-search/cross-icon.svg +6 -0
  3. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-search-tracker.js +4 -0
  4. data/app/assets/javascripts/govuk_publishing_components/components/select-with-search.js +57 -0
  5. data/app/assets/stylesheets/govuk_publishing_components/_all_components.scss +1 -0
  6. data/app/assets/stylesheets/govuk_publishing_components/components/_select-with-search.scss +168 -0
  7. data/app/assets/stylesheets/govuk_publishing_components/components/_select.scss +6 -0
  8. data/app/views/govuk_publishing_components/components/_select.html.erb +22 -23
  9. data/app/views/govuk_publishing_components/components/_select_with_search.html.erb +14 -0
  10. data/app/views/govuk_publishing_components/components/docs/select.yml +11 -0
  11. data/app/views/govuk_publishing_components/components/docs/select_with_search.yml +196 -0
  12. data/lib/govuk_publishing_components/presenters/select_helper.rb +8 -5
  13. data/lib/govuk_publishing_components/presenters/select_with_search_helper.rb +92 -0
  14. data/lib/govuk_publishing_components/version.rb +1 -1
  15. data/lib/govuk_publishing_components.rb +1 -0
  16. data/node_modules/choices.js/LICENSE +21 -0
  17. data/node_modules/choices.js/README.md +1360 -0
  18. data/node_modules/choices.js/package.json +173 -0
  19. data/node_modules/choices.js/public/assets/scripts/choices.js +5230 -0
  20. data/node_modules/choices.js/public/assets/scripts/choices.min.js +2 -0
  21. data/node_modules/choices.js/public/assets/scripts/choices.mjs +5222 -0
  22. data/node_modules/choices.js/public/assets/scripts/choices.search-basic.js +4748 -0
  23. data/node_modules/choices.js/public/assets/scripts/choices.search-basic.min.js +2 -0
  24. data/node_modules/choices.js/public/assets/scripts/choices.search-basic.mjs +4740 -0
  25. data/node_modules/choices.js/public/assets/scripts/choices.search-kmp.js +3631 -0
  26. data/node_modules/choices.js/public/assets/scripts/choices.search-kmp.min.js +2 -0
  27. data/node_modules/choices.js/public/assets/scripts/choices.search-kmp.mjs +3623 -0
  28. data/node_modules/choices.js/public/assets/scripts/choices.search-prefix.js +3590 -0
  29. data/node_modules/choices.js/public/assets/scripts/choices.search-prefix.min.js +2 -0
  30. data/node_modules/choices.js/public/assets/scripts/choices.search-prefix.mjs +3582 -0
  31. data/node_modules/choices.js/public/assets/styles/base.css +180 -0
  32. data/node_modules/choices.js/public/assets/styles/base.css.map +1 -0
  33. data/node_modules/choices.js/public/assets/styles/base.min.css +1 -0
  34. data/node_modules/choices.js/public/assets/styles/choices.css +338 -0
  35. data/node_modules/choices.js/public/assets/styles/choices.css.map +1 -0
  36. data/node_modules/choices.js/public/assets/styles/choices.min.css +1 -0
  37. data/node_modules/choices.js/public/types/src/index.d.ts +6 -0
  38. data/node_modules/choices.js/public/types/src/scripts/actions/choices.d.ts +30 -0
  39. data/node_modules/choices.js/public/types/src/scripts/actions/groups.d.ts +8 -0
  40. data/node_modules/choices.js/public/types/src/scripts/actions/items.d.ts +17 -0
  41. data/node_modules/choices.js/public/types/src/scripts/choices.d.ts +210 -0
  42. data/node_modules/choices.js/public/types/src/scripts/components/container.d.ts +36 -0
  43. data/node_modules/choices.js/public/types/src/scripts/components/dropdown.d.ts +21 -0
  44. data/node_modules/choices.js/public/types/src/scripts/components/index.d.ts +7 -0
  45. data/node_modules/choices.js/public/types/src/scripts/components/input.d.ts +37 -0
  46. data/node_modules/choices.js/public/types/src/scripts/components/list.d.ts +14 -0
  47. data/node_modules/choices.js/public/types/src/scripts/components/wrapped-element.d.ts +21 -0
  48. data/node_modules/choices.js/public/types/src/scripts/components/wrapped-input.d.ts +3 -0
  49. data/node_modules/choices.js/public/types/src/scripts/components/wrapped-select.d.ts +20 -0
  50. data/node_modules/choices.js/public/types/src/scripts/constants.d.ts +1 -0
  51. data/node_modules/choices.js/public/types/src/scripts/defaults.d.ts +4 -0
  52. data/node_modules/choices.js/public/types/src/scripts/interfaces/action-type.d.ts +13 -0
  53. data/node_modules/choices.js/public/types/src/scripts/interfaces/build-flags.d.ts +11 -0
  54. data/node_modules/choices.js/public/types/src/scripts/interfaces/choice-full.d.ts +23 -0
  55. data/node_modules/choices.js/public/types/src/scripts/interfaces/class-names.d.ts +61 -0
  56. data/node_modules/choices.js/public/types/src/scripts/interfaces/event-choice.d.ts +7 -0
  57. data/node_modules/choices.js/public/types/src/scripts/interfaces/event-type.d.ts +14 -0
  58. data/node_modules/choices.js/public/types/src/scripts/interfaces/group-full.d.ts +10 -0
  59. data/node_modules/choices.js/public/types/src/scripts/interfaces/index.d.ts +14 -0
  60. data/node_modules/choices.js/public/types/src/scripts/interfaces/input-choice.d.ts +15 -0
  61. data/node_modules/choices.js/public/types/src/scripts/interfaces/input-group.d.ts +10 -0
  62. data/node_modules/choices.js/public/types/src/scripts/interfaces/item.d.ts +17 -0
  63. data/node_modules/choices.js/public/types/src/scripts/interfaces/keycode-map.d.ts +13 -0
  64. data/node_modules/choices.js/public/types/src/scripts/interfaces/options.d.ts +566 -0
  65. data/node_modules/choices.js/public/types/src/scripts/interfaces/passed-element-type.d.ts +7 -0
  66. data/node_modules/choices.js/public/types/src/scripts/interfaces/passed-element.d.ts +95 -0
  67. data/node_modules/choices.js/public/types/src/scripts/interfaces/position-options-type.d.ts +1 -0
  68. data/node_modules/choices.js/public/types/src/scripts/interfaces/search.d.ts +11 -0
  69. data/node_modules/choices.js/public/types/src/scripts/interfaces/state.d.ts +10 -0
  70. data/node_modules/choices.js/public/types/src/scripts/interfaces/store.d.ts +64 -0
  71. data/node_modules/choices.js/public/types/src/scripts/interfaces/string-pre-escaped.d.ts +3 -0
  72. data/node_modules/choices.js/public/types/src/scripts/interfaces/string-untrusted.d.ts +4 -0
  73. data/node_modules/choices.js/public/types/src/scripts/interfaces/templates.d.ts +29 -0
  74. data/node_modules/choices.js/public/types/src/scripts/interfaces/types.d.ts +18 -0
  75. data/node_modules/choices.js/public/types/src/scripts/lib/choice-input.d.ts +9 -0
  76. data/node_modules/choices.js/public/types/src/scripts/lib/html-guard-statements.d.ts +4 -0
  77. data/node_modules/choices.js/public/types/src/scripts/lib/utils.d.ts +31 -0
  78. data/node_modules/choices.js/public/types/src/scripts/reducers/choices.d.ts +8 -0
  79. data/node_modules/choices.js/public/types/src/scripts/reducers/groups.d.ts +8 -0
  80. data/node_modules/choices.js/public/types/src/scripts/reducers/items.d.ts +9 -0
  81. data/node_modules/choices.js/public/types/src/scripts/search/fuse.d.ts +14 -0
  82. data/node_modules/choices.js/public/types/src/scripts/search/index.d.ts +3 -0
  83. data/node_modules/choices.js/public/types/src/scripts/search/kmp.d.ts +11 -0
  84. data/node_modules/choices.js/public/types/src/scripts/search/prefix-filter.d.ts +11 -0
  85. data/node_modules/choices.js/public/types/src/scripts/store/store.d.ts +59 -0
  86. data/node_modules/choices.js/public/types/src/scripts/templates.d.ts +8 -0
  87. data/node_modules/choices.js/src/entry.js +3 -0
  88. data/node_modules/choices.js/src/icons/cross-inverse.svg +1 -0
  89. data/node_modules/choices.js/src/icons/cross.svg +1 -0
  90. data/node_modules/choices.js/src/index.ts +8 -0
  91. data/node_modules/choices.js/src/scripts/actions/choices.ts +59 -0
  92. data/node_modules/choices.js/src/scripts/actions/groups.ts +14 -0
  93. data/node_modules/choices.js/src/scripts/actions/items.ts +34 -0
  94. data/node_modules/choices.js/src/scripts/choices.ts +2364 -0
  95. data/node_modules/choices.js/src/scripts/components/container.ts +157 -0
  96. data/node_modules/choices.js/src/scripts/components/dropdown.ts +50 -0
  97. data/node_modules/choices.js/src/scripts/components/index.ts +8 -0
  98. data/node_modules/choices.js/src/scripts/components/input.ts +146 -0
  99. data/node_modules/choices.js/src/scripts/components/list.ts +89 -0
  100. data/node_modules/choices.js/src/scripts/components/wrapped-element.ts +89 -0
  101. data/node_modules/choices.js/src/scripts/components/wrapped-input.ts +3 -0
  102. data/node_modules/choices.js/src/scripts/components/wrapped-select.ts +115 -0
  103. data/node_modules/choices.js/src/scripts/constants.ts +1 -0
  104. data/node_modules/choices.js/src/scripts/defaults.ts +93 -0
  105. data/node_modules/choices.js/src/scripts/interfaces/action-type.ts +15 -0
  106. data/node_modules/choices.js/src/scripts/interfaces/build-flags.ts +17 -0
  107. data/node_modules/choices.js/src/scripts/interfaces/choice-full.ts +30 -0
  108. data/node_modules/choices.js/src/scripts/interfaces/class-names.ts +61 -0
  109. data/node_modules/choices.js/src/scripts/interfaces/event-choice.ts +9 -0
  110. data/node_modules/choices.js/src/scripts/interfaces/event-type.ts +16 -0
  111. data/node_modules/choices.js/src/scripts/interfaces/group-full.ts +12 -0
  112. data/node_modules/choices.js/src/scripts/interfaces/index.ts +14 -0
  113. data/node_modules/choices.js/src/scripts/interfaces/input-choice.ts +17 -0
  114. data/node_modules/choices.js/src/scripts/interfaces/input-group.ts +11 -0
  115. data/node_modules/choices.js/src/scripts/interfaces/item.ts +17 -0
  116. data/node_modules/choices.js/src/scripts/interfaces/keycode-map.ts +13 -0
  117. data/node_modules/choices.js/src/scripts/interfaces/options.ts +619 -0
  118. data/node_modules/choices.js/src/scripts/interfaces/passed-element-type.ts +9 -0
  119. data/node_modules/choices.js/src/scripts/interfaces/passed-element.ts +96 -0
  120. data/node_modules/choices.js/src/scripts/interfaces/position-options-type.ts +1 -0
  121. data/node_modules/choices.js/src/scripts/interfaces/search.ts +12 -0
  122. data/node_modules/choices.js/src/scripts/interfaces/state.ts +12 -0
  123. data/node_modules/choices.js/src/scripts/interfaces/store.ts +84 -0
  124. data/node_modules/choices.js/src/scripts/interfaces/string-pre-escaped.ts +3 -0
  125. data/node_modules/choices.js/src/scripts/interfaces/string-untrusted.ts +5 -0
  126. data/node_modules/choices.js/src/scripts/interfaces/templates.ts +66 -0
  127. data/node_modules/choices.js/src/scripts/interfaces/types.ts +21 -0
  128. data/node_modules/choices.js/src/scripts/lib/choice-input.ts +88 -0
  129. data/node_modules/choices.js/src/scripts/lib/html-guard-statements.ts +7 -0
  130. data/node_modules/choices.js/src/scripts/lib/utils.ts +230 -0
  131. data/node_modules/choices.js/src/scripts/reducers/choices.ts +86 -0
  132. data/node_modules/choices.js/src/scripts/reducers/groups.ts +32 -0
  133. data/node_modules/choices.js/src/scripts/reducers/items.ts +86 -0
  134. data/node_modules/choices.js/src/scripts/search/fuse.ts +59 -0
  135. data/node_modules/choices.js/src/scripts/search/index.ts +17 -0
  136. data/node_modules/choices.js/src/scripts/search/kmp.ts +87 -0
  137. data/node_modules/choices.js/src/scripts/search/prefix-filter.ts +42 -0
  138. data/node_modules/choices.js/src/scripts/store/store.ts +184 -0
  139. data/node_modules/choices.js/src/scripts/templates.ts +409 -0
  140. data/node_modules/choices.js/src/styles/base.scss +189 -0
  141. data/node_modules/choices.js/src/styles/choices.scss +414 -0
  142. data/node_modules/choices.js/src/tsconfig.json +22 -0
  143. metadata +134 -1
@@ -0,0 +1,409 @@
1
+ /**
2
+ * Helpers to create HTML elements used by Choices
3
+ * Can be overridden by providing `callbackOnCreateTemplates` option.
4
+ * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`
5
+ */
6
+
7
+ import { ChoiceFull } from './interfaces/choice-full';
8
+ import { GroupFull } from './interfaces/group-full';
9
+ import { PassedElementType } from './interfaces/passed-element-type';
10
+ import { StringPreEscaped } from './interfaces/string-pre-escaped';
11
+ import {
12
+ getClassNames,
13
+ unwrapStringForRaw,
14
+ resolveNoticeFunction,
15
+ setElementHtml,
16
+ escapeForTemplate,
17
+ addClassesToElement,
18
+ removeClassesFromElement,
19
+ } from './lib/utils';
20
+ import { NoticeType, NoticeTypes, TemplateOptions, Templates as TemplatesInterface } from './interfaces/templates';
21
+ import { StringUntrusted } from './interfaces/string-untrusted';
22
+
23
+ const isEmptyObject = (obj: object): boolean => {
24
+ // eslint-disable-next-line no-restricted-syntax
25
+ for (const prop in obj) {
26
+ if (Object.prototype.hasOwnProperty.call(obj, prop)) {
27
+ return false;
28
+ }
29
+ }
30
+
31
+ return true;
32
+ };
33
+
34
+ const assignCustomProperties = (el: HTMLElement, choice: ChoiceFull, withCustomProperties: boolean): void => {
35
+ const { dataset } = el;
36
+ const { customProperties, labelClass, labelDescription } = choice;
37
+
38
+ if (labelClass) {
39
+ dataset.labelClass = getClassNames(labelClass).join(' ');
40
+ }
41
+
42
+ if (labelDescription) {
43
+ dataset.labelDescription = labelDescription;
44
+ }
45
+
46
+ if (withCustomProperties && customProperties) {
47
+ if (typeof customProperties === 'string') {
48
+ dataset.customProperties = customProperties;
49
+ } else if (typeof customProperties === 'object' && !isEmptyObject(customProperties)) {
50
+ dataset.customProperties = JSON.stringify(customProperties);
51
+ }
52
+ }
53
+ };
54
+
55
+ const addAriaLabel = (docRoot: HTMLElement | ShadowRoot, id: string | undefined, element: HTMLElement): void => {
56
+ const label = id && docRoot.querySelector<HTMLElement>(`label[for='${id}']`);
57
+ const text = label && (label as HTMLElement).innerText;
58
+ if (text) {
59
+ element.setAttribute('aria-label', text);
60
+ }
61
+ };
62
+
63
+ const templates: TemplatesInterface = {
64
+ containerOuter(
65
+ { classNames: { containerOuter } }: TemplateOptions,
66
+ dir: HTMLElement['dir'],
67
+ isSelectElement: boolean,
68
+ isSelectOneElement: boolean,
69
+ searchEnabled: boolean,
70
+ passedElementType: PassedElementType,
71
+ labelId: string,
72
+ ): HTMLDivElement {
73
+ const div = document.createElement('div');
74
+ addClassesToElement(div, containerOuter);
75
+
76
+ div.dataset.type = passedElementType;
77
+
78
+ if (dir) {
79
+ div.dir = dir;
80
+ }
81
+
82
+ if (isSelectOneElement) {
83
+ div.tabIndex = 0;
84
+ }
85
+
86
+ if (isSelectElement) {
87
+ div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox');
88
+ if (searchEnabled) {
89
+ div.setAttribute('aria-autocomplete', 'list');
90
+ } else if (!labelId) {
91
+ addAriaLabel(this._docRoot, this.passedElement.element.id, div);
92
+ }
93
+
94
+ div.setAttribute('aria-haspopup', 'true');
95
+ div.setAttribute('aria-expanded', 'false');
96
+ }
97
+
98
+ if (labelId) {
99
+ div.setAttribute('aria-labelledby', labelId);
100
+ }
101
+
102
+ return div;
103
+ },
104
+
105
+ containerInner({ classNames: { containerInner } }: TemplateOptions): HTMLDivElement {
106
+ const div = document.createElement('div');
107
+ addClassesToElement(div, containerInner);
108
+
109
+ return div;
110
+ },
111
+
112
+ itemList(
113
+ { searchEnabled, classNames: { list, listSingle, listItems } }: TemplateOptions,
114
+ isSelectOneElement: boolean,
115
+ ): HTMLDivElement {
116
+ const div = document.createElement('div');
117
+ addClassesToElement(div, list);
118
+ addClassesToElement(div, isSelectOneElement ? listSingle : listItems);
119
+
120
+ if (this._isSelectElement && searchEnabled) {
121
+ div.setAttribute('role', 'listbox');
122
+ }
123
+
124
+ return div;
125
+ },
126
+
127
+ placeholder(
128
+ { allowHTML, classNames: { placeholder } }: TemplateOptions,
129
+ value: StringPreEscaped | string,
130
+ ): HTMLDivElement {
131
+ const div = document.createElement('div');
132
+ addClassesToElement(div, placeholder);
133
+ setElementHtml(div, allowHTML, value);
134
+
135
+ return div;
136
+ },
137
+
138
+ item(
139
+ {
140
+ allowHTML,
141
+ removeItemButtonAlignLeft,
142
+ removeItemIconText,
143
+ removeItemLabelText,
144
+ classNames: { item, button, highlightedState, itemSelectable, placeholder },
145
+ }: TemplateOptions,
146
+ choice: ChoiceFull,
147
+ removeItemButton: boolean,
148
+ ): HTMLDivElement {
149
+ const rawValue = unwrapStringForRaw(choice.value);
150
+ const div = document.createElement('div');
151
+ addClassesToElement(div, item);
152
+
153
+ if (choice.labelClass) {
154
+ const spanLabel = document.createElement('span');
155
+ setElementHtml(spanLabel, allowHTML, choice.label);
156
+ addClassesToElement(spanLabel, choice.labelClass);
157
+ div.appendChild(spanLabel);
158
+ } else {
159
+ setElementHtml(div, allowHTML, choice.label);
160
+ }
161
+
162
+ div.dataset.item = '';
163
+ div.dataset.id = choice.id as unknown as string;
164
+ div.dataset.value = rawValue;
165
+
166
+ assignCustomProperties(div, choice, true);
167
+
168
+ if (choice.disabled || this.containerOuter.isDisabled) {
169
+ div.setAttribute('aria-disabled', 'true');
170
+ }
171
+ if (this._isSelectElement) {
172
+ div.setAttribute('aria-selected', 'true');
173
+ div.setAttribute('role', 'option');
174
+ }
175
+
176
+ if (choice.placeholder) {
177
+ addClassesToElement(div, placeholder);
178
+ div.dataset.placeholder = '';
179
+ }
180
+
181
+ addClassesToElement(div, choice.highlighted ? highlightedState : itemSelectable);
182
+
183
+ if (removeItemButton) {
184
+ if (choice.disabled) {
185
+ removeClassesFromElement(div, itemSelectable);
186
+ }
187
+ div.dataset.deletable = '';
188
+
189
+ const removeButton = document.createElement('button');
190
+ removeButton.type = 'button';
191
+ addClassesToElement(removeButton, button);
192
+ setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value));
193
+
194
+ const REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value);
195
+ if (REMOVE_ITEM_LABEL) {
196
+ removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);
197
+ }
198
+ removeButton.dataset.button = '';
199
+ if (removeItemButtonAlignLeft) {
200
+ div.insertAdjacentElement('afterbegin', removeButton);
201
+ } else {
202
+ div.appendChild(removeButton);
203
+ }
204
+ }
205
+
206
+ return div;
207
+ },
208
+
209
+ choiceList({ classNames: { list } }: TemplateOptions, isSelectOneElement: boolean): HTMLDivElement {
210
+ const div = document.createElement('div');
211
+ addClassesToElement(div, list);
212
+
213
+ if (!isSelectOneElement) {
214
+ div.setAttribute('aria-multiselectable', 'true');
215
+ }
216
+ div.setAttribute('role', 'listbox');
217
+
218
+ return div;
219
+ },
220
+
221
+ choiceGroup(
222
+ { allowHTML, classNames: { group, groupHeading, itemDisabled } }: TemplateOptions,
223
+ { id, label, disabled }: GroupFull,
224
+ ): HTMLDivElement {
225
+ const rawLabel = unwrapStringForRaw(label);
226
+ const div = document.createElement('div');
227
+ addClassesToElement(div, group);
228
+ if (disabled) {
229
+ addClassesToElement(div, itemDisabled);
230
+ }
231
+
232
+ div.setAttribute('role', 'group');
233
+
234
+ div.dataset.group = '';
235
+ div.dataset.id = id as unknown as string;
236
+ div.dataset.value = rawLabel;
237
+
238
+ if (disabled) {
239
+ div.setAttribute('aria-disabled', 'true');
240
+ }
241
+
242
+ const heading = document.createElement('div');
243
+ addClassesToElement(heading, groupHeading);
244
+ setElementHtml(heading, allowHTML, label || '');
245
+ div.appendChild(heading);
246
+
247
+ return div;
248
+ },
249
+
250
+ choice(
251
+ {
252
+ allowHTML,
253
+ classNames: { item, itemChoice, itemSelectable, selectedState, itemDisabled, description, placeholder },
254
+ }: TemplateOptions,
255
+ choice: ChoiceFull,
256
+ selectText: string,
257
+ groupName?: string,
258
+ ): HTMLDivElement {
259
+ // eslint-disable-next-line prefer-destructuring
260
+ let label: string | StringUntrusted | StringPreEscaped = choice.label;
261
+ const rawValue = unwrapStringForRaw(choice.value);
262
+ const div = document.createElement('div');
263
+ div.id = choice.elementId as string;
264
+ addClassesToElement(div, item);
265
+ addClassesToElement(div, itemChoice);
266
+
267
+ if (groupName && typeof label === 'string') {
268
+ label = escapeForTemplate(allowHTML, label);
269
+ label += ` (${groupName})`;
270
+ label = { trusted: label };
271
+ }
272
+
273
+ let describedBy: HTMLElement = div;
274
+ if (choice.labelClass) {
275
+ const spanLabel = document.createElement('span');
276
+ setElementHtml(spanLabel, allowHTML, label);
277
+ addClassesToElement(spanLabel, choice.labelClass);
278
+ describedBy = spanLabel;
279
+ div.appendChild(spanLabel);
280
+ } else {
281
+ setElementHtml(div, allowHTML, label);
282
+ }
283
+
284
+ if (choice.labelDescription) {
285
+ const descId = `${choice.elementId}-description`;
286
+ describedBy.setAttribute('aria-describedby', descId);
287
+ const spanDesc = document.createElement('span');
288
+ setElementHtml(spanDesc, allowHTML, choice.labelDescription);
289
+ spanDesc.id = descId;
290
+ addClassesToElement(spanDesc, description);
291
+ div.appendChild(spanDesc);
292
+ }
293
+
294
+ if (choice.selected) {
295
+ addClassesToElement(div, selectedState);
296
+ }
297
+
298
+ if (choice.placeholder) {
299
+ addClassesToElement(div, placeholder);
300
+ }
301
+
302
+ div.setAttribute('role', choice.group ? 'treeitem' : 'option');
303
+
304
+ div.dataset.choice = '';
305
+ div.dataset.id = choice.id as unknown as string;
306
+ div.dataset.value = rawValue;
307
+ if (selectText) {
308
+ div.dataset.selectText = selectText;
309
+ }
310
+ if (choice.group) {
311
+ div.dataset.groupId = `${choice.group.id}`;
312
+ }
313
+
314
+ assignCustomProperties(div, choice, false);
315
+
316
+ if (choice.disabled) {
317
+ addClassesToElement(div, itemDisabled);
318
+ div.dataset.choiceDisabled = '';
319
+ div.setAttribute('aria-disabled', 'true');
320
+ } else {
321
+ addClassesToElement(div, itemSelectable);
322
+ div.dataset.choiceSelectable = '';
323
+ }
324
+
325
+ return div;
326
+ },
327
+
328
+ input(
329
+ { classNames: { input, inputCloned }, labelId }: TemplateOptions,
330
+ placeholderValue: string | null,
331
+ ): HTMLInputElement {
332
+ const inp = document.createElement('input');
333
+ inp.type = 'search';
334
+ addClassesToElement(inp, input);
335
+ addClassesToElement(inp, inputCloned);
336
+ inp.autocomplete = 'off';
337
+ inp.autocapitalize = 'off';
338
+ inp.spellcheck = false;
339
+
340
+ inp.setAttribute('aria-autocomplete', 'list');
341
+ if (placeholderValue) {
342
+ inp.setAttribute('aria-label', placeholderValue);
343
+ } else if (!labelId) {
344
+ addAriaLabel(this._docRoot, this.passedElement.element.id, inp);
345
+ }
346
+
347
+ return inp;
348
+ },
349
+
350
+ dropdown({ classNames: { list, listDropdown } }: TemplateOptions): HTMLDivElement {
351
+ const div = document.createElement('div');
352
+
353
+ addClassesToElement(div, list);
354
+ addClassesToElement(div, listDropdown);
355
+ div.setAttribute('aria-expanded', 'false');
356
+
357
+ return div;
358
+ },
359
+
360
+ notice(
361
+ { classNames: { item, itemChoice, addChoice, noResults, noChoices, notice: noticeItem } }: TemplateOptions,
362
+ innerHTML: string,
363
+ type: NoticeType = NoticeTypes.generic,
364
+ ): HTMLDivElement {
365
+ const notice = document.createElement('div');
366
+ setElementHtml(notice, true, innerHTML);
367
+
368
+ addClassesToElement(notice, item);
369
+ addClassesToElement(notice, itemChoice);
370
+ addClassesToElement(notice, noticeItem);
371
+
372
+ // eslint-disable-next-line default-case
373
+ switch (type) {
374
+ case NoticeTypes.addChoice:
375
+ addClassesToElement(notice, addChoice);
376
+ break;
377
+ case NoticeTypes.noResults:
378
+ addClassesToElement(notice, noResults);
379
+ break;
380
+ case NoticeTypes.noChoices:
381
+ addClassesToElement(notice, noChoices);
382
+ break;
383
+ }
384
+
385
+ if (type === NoticeTypes.addChoice) {
386
+ notice.dataset.choiceSelectable = '';
387
+ notice.dataset.choice = '';
388
+ }
389
+
390
+ return notice;
391
+ },
392
+
393
+ option(choice: ChoiceFull): HTMLOptionElement {
394
+ // HtmlOptionElement's label value does not support HTML, so the avoid double escaping unwrap the untrusted string.
395
+ const labelValue = unwrapStringForRaw(choice.label);
396
+
397
+ const opt = new Option(labelValue, choice.value, false, choice.selected);
398
+ assignCustomProperties(opt, choice, true);
399
+
400
+ opt.disabled = choice.disabled;
401
+ if (choice.selected) {
402
+ opt.setAttribute('selected', '');
403
+ }
404
+
405
+ return opt;
406
+ },
407
+ };
408
+
409
+ export default templates;
@@ -0,0 +1,189 @@
1
+ /* =============================================
2
+ = Generic styling =
3
+ ============================================= */
4
+
5
+ $global-guttering: 24px;
6
+ $global-font-size-h1: 32px;
7
+ $global-font-size-h2: 24px;
8
+ $global-font-size-h3: 20px;
9
+ $global-font-size-h4: 18px;
10
+ $global-font-size-h5: 16px;
11
+ $global-font-size-h6: 14px;
12
+
13
+ * {
14
+ -webkit-font-smoothing: antialiased;
15
+ -moz-osx-font-smoothing: grayscale;
16
+ }
17
+
18
+ *,
19
+ *::before,
20
+ *::after {
21
+ box-sizing: border-box;
22
+ }
23
+
24
+ html,
25
+ body {
26
+ position: relative;
27
+ margin: 0;
28
+ width: 100%;
29
+ height: 100%;
30
+ }
31
+
32
+ body {
33
+ font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
34
+ font-size: 16px;
35
+ line-height: 1.4;
36
+ color: #fff;
37
+ background-color: #333;
38
+ overflow-x: hidden;
39
+ }
40
+
41
+ label {
42
+ display: block;
43
+ margin-bottom: 8px;
44
+ font-size: 14px;
45
+ font-weight: 500;
46
+ cursor: pointer;
47
+ }
48
+
49
+ p {
50
+ margin-top: 0;
51
+ margin-bottom: 8px;
52
+ }
53
+
54
+ hr {
55
+ display: block;
56
+ margin: $global-guttering * 1.25 0;
57
+ border: 0;
58
+ border-bottom: 1px solid #eaeaea;
59
+ height: 1px;
60
+ }
61
+
62
+ h1,
63
+ h2,
64
+ h3,
65
+ h4,
66
+ h5,
67
+ h6 {
68
+ margin-top: 0;
69
+ margin-bottom: $global-guttering * 0.5;
70
+ font-weight: 400;
71
+ line-height: 1.2;
72
+ }
73
+
74
+ a,
75
+ a:visited,
76
+ a:focus {
77
+ color: #fff;
78
+ text-decoration: none;
79
+ font-weight: 600;
80
+ }
81
+
82
+ .form-control {
83
+ display: block;
84
+ width: 100%;
85
+ background-color: #f9f9f9;
86
+ padding: 12px;
87
+ border: 1px solid #ddd;
88
+ border-radius: 2.5px;
89
+ font-size: 14px;
90
+ appearance: none;
91
+ margin-bottom: $global-guttering;
92
+ }
93
+
94
+ h1,
95
+ .h1 {
96
+ font-size: $global-font-size-h1;
97
+ }
98
+
99
+ h2,
100
+ .h2 {
101
+ font-size: $global-font-size-h2;
102
+ }
103
+
104
+ h3,
105
+ .h3 {
106
+ font-size: $global-font-size-h3;
107
+ }
108
+
109
+ h4,
110
+ .h4 {
111
+ font-size: $global-font-size-h4;
112
+ }
113
+
114
+ h5,
115
+ .h5 {
116
+ font-size: $global-font-size-h5;
117
+ }
118
+
119
+ h6,
120
+ .h6 {
121
+ font-size: $global-font-size-h6;
122
+ }
123
+
124
+ label + p {
125
+ margin-top: -4px;
126
+ }
127
+
128
+ .container {
129
+ display: block;
130
+ margin: auto;
131
+ max-width: 40em;
132
+ padding: $global-guttering * 2;
133
+
134
+ @media (max-width: 620px) {
135
+ padding: 0;
136
+ }
137
+ }
138
+
139
+ .section {
140
+ background-color: #fff;
141
+ padding: $global-guttering;
142
+ color: #333;
143
+
144
+ a,
145
+ a:visited,
146
+ a:focus {
147
+ color: #005F75;
148
+ }
149
+ }
150
+
151
+ .logo {
152
+ display: block;
153
+ margin-bottom: $global-guttering * 0.5;
154
+ }
155
+
156
+ .logo-img {
157
+ width: 100%;
158
+ height: auto;
159
+ display: inline-block;
160
+ max-width: 100%;
161
+ vertical-align: top;
162
+ padding: $global-guttering * 0.25 0;
163
+ }
164
+
165
+ .visible-ie {
166
+ display: none;
167
+ }
168
+
169
+ .push-bottom {
170
+ margin-bottom: $global-guttering;
171
+ }
172
+
173
+ .zero-bottom {
174
+ margin-bottom: 0;
175
+ }
176
+
177
+ .zero-top {
178
+ margin-top: 0;
179
+ }
180
+
181
+ .text-center {
182
+ text-align: center;
183
+ }
184
+
185
+ [data-test-hook] {
186
+ margin-bottom: $global-guttering;
187
+ }
188
+
189
+ /* ===== End of Section comment block ====== */