@ministryofjustice/frontend 4.0.1 → 5.1.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 (256) hide show
  1. package/govuk-prototype-kit.config.json +19 -4
  2. package/moj/_base.scss +2 -0
  3. package/moj/_base.scss.map +1 -0
  4. package/moj/all.bundle.js +3010 -0
  5. package/moj/all.bundle.js.map +1 -0
  6. package/moj/all.bundle.mjs +3293 -0
  7. package/moj/all.bundle.mjs.map +1 -0
  8. package/moj/all.mjs +17 -110
  9. package/moj/all.mjs.map +1 -1
  10. package/moj/all.scss +3 -0
  11. package/moj/all.scss.map +1 -0
  12. package/moj/common/index.mjs +57 -0
  13. package/moj/common/index.mjs.map +1 -0
  14. package/moj/common/moj-frontend-version.mjs +14 -0
  15. package/moj/common/moj-frontend-version.mjs.map +1 -0
  16. package/moj/components/_all.scss +2 -0
  17. package/moj/components/_all.scss.map +1 -0
  18. package/moj/components/action-bar/_action-bar.scss +2 -0
  19. package/moj/components/action-bar/_action-bar.scss.map +1 -0
  20. package/moj/components/add-another/_add-another.scss +2 -0
  21. package/moj/components/add-another/_add-another.scss.map +1 -0
  22. package/moj/components/add-another/add-another.bundle.js +157 -0
  23. package/moj/components/add-another/add-another.bundle.js.map +1 -0
  24. package/moj/components/add-another/add-another.bundle.mjs +271 -0
  25. package/moj/components/add-another/add-another.bundle.mjs.map +1 -0
  26. package/moj/components/add-another/add-another.mjs +135 -91
  27. package/moj/components/add-another/add-another.mjs.map +1 -1
  28. package/moj/components/alert/_alert.scss +4 -0
  29. package/moj/components/alert/_alert.scss.map +1 -0
  30. package/moj/components/alert/alert.bundle.js +254 -0
  31. package/moj/components/alert/alert.bundle.js.map +1 -0
  32. package/moj/components/alert/alert.bundle.mjs +490 -0
  33. package/moj/components/alert/alert.bundle.mjs.map +1 -0
  34. package/moj/components/alert/alert.mjs +97 -218
  35. package/moj/components/alert/alert.mjs.map +1 -1
  36. package/moj/components/alert/{alert.spec.helper.js → alert.spec.helper.bundle.js} +1 -1
  37. package/moj/components/alert/alert.spec.helper.bundle.js.map +1 -0
  38. package/moj/components/alert/alert.spec.helper.bundle.mjs +67 -0
  39. package/moj/components/alert/alert.spec.helper.bundle.mjs.map +1 -0
  40. package/moj/components/alert/alert.spec.helper.mjs.map +1 -1
  41. package/moj/components/badge/_badge.scss +2 -0
  42. package/moj/components/badge/_badge.scss.map +1 -0
  43. package/moj/components/banner/_banner.scss +2 -0
  44. package/moj/components/banner/_banner.scss.map +1 -0
  45. package/moj/components/button-menu/README.md +12 -6
  46. package/moj/components/button-menu/_button-menu.scss +4 -1
  47. package/moj/components/button-menu/_button-menu.scss.map +1 -0
  48. package/moj/components/button-menu/button-menu.bundle.js +270 -0
  49. package/moj/components/button-menu/button-menu.bundle.js.map +1 -0
  50. package/moj/components/button-menu/button-menu.bundle.mjs +506 -0
  51. package/moj/components/button-menu/button-menu.bundle.mjs.map +1 -0
  52. package/moj/components/button-menu/button-menu.mjs +214 -280
  53. package/moj/components/button-menu/button-menu.mjs.map +1 -1
  54. package/moj/components/cookie-banner/_cookie-banner.scss +2 -0
  55. package/moj/components/cookie-banner/_cookie-banner.scss.map +1 -0
  56. package/moj/components/currency-input/_currency-input.scss +2 -0
  57. package/moj/components/currency-input/_currency-input.scss.map +1 -0
  58. package/moj/components/date-picker/_date-picker.scss +2 -0
  59. package/moj/components/date-picker/_date-picker.scss.map +1 -0
  60. package/moj/components/date-picker/date-picker.bundle.js +804 -0
  61. package/moj/components/date-picker/date-picker.bundle.js.map +1 -0
  62. package/moj/components/date-picker/date-picker.bundle.mjs +1040 -0
  63. package/moj/components/date-picker/date-picker.bundle.mjs.map +1 -0
  64. package/moj/components/date-picker/date-picker.mjs +663 -827
  65. package/moj/components/date-picker/date-picker.mjs.map +1 -1
  66. package/moj/components/filter/_filter.scss +2 -0
  67. package/moj/components/filter/_filter.scss.map +1 -0
  68. package/moj/components/filter/template.njk +1 -1
  69. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js +185 -0
  70. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js.map +1 -0
  71. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs +421 -0
  72. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs.map +1 -0
  73. package/moj/components/filter-toggle-button/filter-toggle-button.mjs +166 -81
  74. package/moj/components/filter-toggle-button/filter-toggle-button.mjs.map +1 -1
  75. package/moj/components/form-validator/form-validator.bundle.js +288 -0
  76. package/moj/components/form-validator/form-validator.bundle.js.map +1 -0
  77. package/moj/components/form-validator/form-validator.bundle.mjs +524 -0
  78. package/moj/components/form-validator/form-validator.bundle.mjs.map +1 -0
  79. package/moj/components/form-validator/form-validator.mjs +226 -149
  80. package/moj/components/form-validator/form-validator.mjs.map +1 -1
  81. package/moj/components/header/_header.scss +2 -0
  82. package/moj/components/header/_header.scss.map +1 -0
  83. package/moj/components/identity-bar/_identity-bar.scss +2 -0
  84. package/moj/components/identity-bar/_identity-bar.scss.map +1 -0
  85. package/moj/components/interruption-card/_interruption-card.scss +2 -0
  86. package/moj/components/interruption-card/_interruption-card.scss.map +1 -0
  87. package/moj/components/messages/_messages.scss +2 -0
  88. package/moj/components/messages/_messages.scss.map +1 -0
  89. package/moj/components/multi-file-upload/_multi-file-upload.scss +2 -0
  90. package/moj/components/multi-file-upload/_multi-file-upload.scss.map +1 -0
  91. package/moj/components/multi-file-upload/multi-file-upload.bundle.js +397 -0
  92. package/moj/components/multi-file-upload/multi-file-upload.bundle.js.map +1 -0
  93. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs +633 -0
  94. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs.map +1 -0
  95. package/moj/components/multi-file-upload/multi-file-upload.mjs +384 -213
  96. package/moj/components/multi-file-upload/multi-file-upload.mjs.map +1 -1
  97. package/moj/components/multi-file-upload/template.njk +1 -1
  98. package/moj/components/multi-select/_multi-select.scss +2 -0
  99. package/moj/components/multi-select/_multi-select.scss.map +1 -0
  100. package/moj/components/multi-select/multi-select.bundle.js +143 -0
  101. package/moj/components/multi-select/multi-select.bundle.js.map +1 -0
  102. package/moj/components/multi-select/multi-select.bundle.mjs +379 -0
  103. package/moj/components/multi-select/multi-select.bundle.mjs.map +1 -0
  104. package/moj/components/multi-select/multi-select.mjs +123 -64
  105. package/moj/components/multi-select/multi-select.mjs.map +1 -1
  106. package/moj/components/notification-badge/_notification-badge.scss +2 -0
  107. package/moj/components/notification-badge/_notification-badge.scss.map +1 -0
  108. package/moj/components/organisation-switcher/_organisation-switcher.scss +2 -0
  109. package/moj/components/organisation-switcher/_organisation-switcher.scss.map +1 -0
  110. package/moj/components/page-header-actions/_page-header-actions.scss +2 -0
  111. package/moj/components/page-header-actions/_page-header-actions.scss.map +1 -0
  112. package/moj/components/pagination/_pagination.scss +2 -2
  113. package/moj/components/pagination/_pagination.scss.map +1 -0
  114. package/moj/components/password-reveal/_password-reveal.scss +5 -1
  115. package/moj/components/password-reveal/_password-reveal.scss.map +1 -0
  116. package/moj/components/password-reveal/password-reveal.bundle.js +52 -0
  117. package/moj/components/password-reveal/password-reveal.bundle.js.map +1 -0
  118. package/moj/components/password-reveal/password-reveal.bundle.mjs +166 -0
  119. package/moj/components/password-reveal/password-reveal.bundle.mjs.map +1 -0
  120. package/moj/components/password-reveal/password-reveal.mjs +39 -29
  121. package/moj/components/password-reveal/password-reveal.mjs.map +1 -1
  122. package/moj/components/primary-navigation/_primary-navigation.scss +2 -0
  123. package/moj/components/primary-navigation/_primary-navigation.scss.map +1 -0
  124. package/moj/components/progress-bar/_progress-bar.scss +2 -0
  125. package/moj/components/progress-bar/_progress-bar.scss.map +1 -0
  126. package/moj/components/rich-text-editor/README.md +16 -9
  127. package/moj/components/rich-text-editor/_rich-text-editor.scss +2 -0
  128. package/moj/components/rich-text-editor/_rich-text-editor.scss.map +1 -0
  129. package/moj/components/rich-text-editor/rich-text-editor.bundle.js +210 -0
  130. package/moj/components/rich-text-editor/rich-text-editor.bundle.js.map +1 -0
  131. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs +446 -0
  132. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs.map +1 -0
  133. package/moj/components/rich-text-editor/rich-text-editor.mjs +186 -140
  134. package/moj/components/rich-text-editor/rich-text-editor.mjs.map +1 -1
  135. package/moj/components/search/_search.scss +2 -0
  136. package/moj/components/search/_search.scss.map +1 -0
  137. package/moj/components/search-toggle/{search-toggle.scss → _search-toggle.scss} +2 -0
  138. package/moj/components/search-toggle/_search-toggle.scss.map +1 -0
  139. package/moj/components/search-toggle/search-toggle.bundle.js +122 -0
  140. package/moj/components/search-toggle/search-toggle.bundle.js.map +1 -0
  141. package/moj/components/search-toggle/search-toggle.bundle.mjs +358 -0
  142. package/moj/components/search-toggle/search-toggle.bundle.mjs.map +1 -0
  143. package/moj/components/search-toggle/search-toggle.mjs +104 -43
  144. package/moj/components/search-toggle/search-toggle.mjs.map +1 -1
  145. package/moj/components/side-navigation/_side-navigation.scss +2 -0
  146. package/moj/components/side-navigation/_side-navigation.scss.map +1 -0
  147. package/moj/components/sortable-table/_sortable-table.scss +2 -2
  148. package/moj/components/sortable-table/_sortable-table.scss.map +1 -0
  149. package/moj/components/sortable-table/sortable-table.bundle.js +202 -0
  150. package/moj/components/sortable-table/sortable-table.bundle.js.map +1 -0
  151. package/moj/components/sortable-table/sortable-table.bundle.mjs +438 -0
  152. package/moj/components/sortable-table/sortable-table.bundle.mjs.map +1 -0
  153. package/moj/components/sortable-table/sortable-table.mjs +179 -122
  154. package/moj/components/sortable-table/sortable-table.mjs.map +1 -1
  155. package/moj/components/sub-navigation/_sub-navigation.scss +2 -0
  156. package/moj/components/sub-navigation/_sub-navigation.scss.map +1 -0
  157. package/moj/components/tag/_tag.scss +2 -0
  158. package/moj/components/tag/_tag.scss.map +1 -0
  159. package/moj/components/task-list/_task-list.scss +2 -0
  160. package/moj/components/task-list/_task-list.scss.map +1 -0
  161. package/moj/components/ticket-panel/_ticket-panel.scss +2 -0
  162. package/moj/components/ticket-panel/_ticket-panel.scss.map +1 -0
  163. package/moj/components/timeline/_timeline.scss +2 -0
  164. package/moj/components/timeline/_timeline.scss.map +1 -0
  165. package/moj/core/_all.scss +3 -0
  166. package/moj/core/_all.scss.map +1 -0
  167. package/moj/core/_moj-frontend-properties.scss +7 -0
  168. package/moj/core/_moj-frontend-properties.scss.map +1 -0
  169. package/moj/filters/all.js +44 -22
  170. package/moj/filters/prototype-kit-13-filters.js +4 -3
  171. package/moj/helpers/_all.scss +2 -0
  172. package/moj/helpers/_all.scss.map +1 -0
  173. package/moj/helpers/_hidden.scss +2 -0
  174. package/moj/helpers/_hidden.scss.map +1 -0
  175. package/moj/helpers/_links.scss +2 -0
  176. package/moj/helpers/_links.scss.map +1 -0
  177. package/moj/helpers.bundle.js +140 -0
  178. package/moj/helpers.bundle.js.map +1 -0
  179. package/moj/helpers.bundle.mjs +128 -0
  180. package/moj/helpers.bundle.mjs.map +1 -0
  181. package/moj/helpers.mjs +50 -77
  182. package/moj/helpers.mjs.map +1 -1
  183. package/moj/init.js +11 -2
  184. package/moj/moj-frontend.min.css +1 -1
  185. package/moj/moj-frontend.min.css.map +1 -1
  186. package/moj/moj-frontend.min.js +1 -1
  187. package/moj/moj-frontend.min.js.map +1 -1
  188. package/moj/objects/_all.scss +2 -0
  189. package/moj/objects/_all.scss.map +1 -0
  190. package/moj/objects/_button-group.scss +2 -0
  191. package/moj/objects/_button-group.scss.map +1 -0
  192. package/moj/objects/_filter-layout.scss +2 -0
  193. package/moj/objects/_filter-layout.scss.map +1 -0
  194. package/moj/objects/_scrollable-pane.scss +2 -0
  195. package/moj/objects/_scrollable-pane.scss.map +1 -0
  196. package/moj/objects/_width-container.scss +2 -0
  197. package/moj/objects/_width-container.scss.map +1 -0
  198. package/moj/settings/_all.scss +2 -0
  199. package/moj/settings/_all.scss.map +1 -0
  200. package/moj/settings/_assets.scss +2 -0
  201. package/moj/settings/_assets.scss.map +1 -0
  202. package/moj/settings/_colours.scss +2 -0
  203. package/moj/settings/_colours.scss.map +1 -0
  204. package/moj/settings/_measurements.scss +2 -0
  205. package/moj/settings/_measurements.scss.map +1 -0
  206. package/moj/settings/_typography.scss +2 -0
  207. package/moj/settings/_typography.scss.map +1 -0
  208. package/moj/template.njk +13 -0
  209. package/moj/utilities/_all.scss +2 -0
  210. package/moj/utilities/_all.scss.map +1 -0
  211. package/moj/utilities/_hidden.scss +2 -0
  212. package/moj/utilities/_hidden.scss.map +1 -0
  213. package/moj/utilities/_width-container.scss +2 -0
  214. package/moj/utilities/_width-container.scss.map +1 -0
  215. package/moj/vendor/govuk-frontend/_base.scss +2 -0
  216. package/moj/vendor/govuk-frontend/_base.scss.map +1 -0
  217. package/moj/vendor/govuk-frontend/_index.scss +2 -0
  218. package/moj/vendor/govuk-frontend/_index.scss.map +1 -0
  219. package/package.json +5 -6
  220. package/moj/all.jquery.min.js +0 -1
  221. package/moj/all.jquery.min.js.map +0 -1
  222. package/moj/all.js +0 -2662
  223. package/moj/all.js.map +0 -1
  224. package/moj/components/add-another/add-another.js +0 -115
  225. package/moj/components/add-another/add-another.js.map +0 -1
  226. package/moj/components/alert/alert.js +0 -356
  227. package/moj/components/alert/alert.js.map +0 -1
  228. package/moj/components/alert/alert.spec.helper.js.map +0 -1
  229. package/moj/components/button-menu/button-menu.js +0 -338
  230. package/moj/components/button-menu/button-menu.js.map +0 -1
  231. package/moj/components/date-picker/date-picker.js +0 -970
  232. package/moj/components/date-picker/date-picker.js.map +0 -1
  233. package/moj/components/filter-toggle-button/filter-toggle-button.js +0 -102
  234. package/moj/components/filter-toggle-button/filter-toggle-button.js.map +0 -1
  235. package/moj/components/form-validator/form-validator.js +0 -205
  236. package/moj/components/form-validator/form-validator.js.map +0 -1
  237. package/moj/components/multi-file-upload/multi-file-upload.js +0 -241
  238. package/moj/components/multi-file-upload/multi-file-upload.js.map +0 -1
  239. package/moj/components/multi-select/multi-select.js +0 -86
  240. package/moj/components/multi-select/multi-select.js.map +0 -1
  241. package/moj/components/password-reveal/password-reveal.js +0 -44
  242. package/moj/components/password-reveal/password-reveal.js.map +0 -1
  243. package/moj/components/rich-text-editor/rich-text-editor.js +0 -166
  244. package/moj/components/rich-text-editor/rich-text-editor.js.map +0 -1
  245. package/moj/components/search-toggle/search-toggle.js +0 -63
  246. package/moj/components/search-toggle/search-toggle.js.map +0 -1
  247. package/moj/components/sortable-table/sortable-table.js +0 -147
  248. package/moj/components/sortable-table/sortable-table.js.map +0 -1
  249. package/moj/helpers.js +0 -200
  250. package/moj/helpers.js.map +0 -1
  251. package/moj/vendor/html5shiv.js +0 -326
  252. package/moj/vendor/jquery.js +0 -9300
  253. package/moj/version.js +0 -12
  254. package/moj/version.js.map +0 -1
  255. package/moj/version.mjs +0 -4
  256. package/moj/version.mjs.map +0 -1
@@ -1,158 +1,204 @@
1
- function RichTextEditor(options) {
2
- if (!('contentEditable' in document.documentElement)) {
3
- return
1
+ import { ConfigurableComponent } from 'govuk-frontend';
2
+
3
+ /**
4
+ * @augments {ConfigurableComponent<RichTextEditorConfig>}
5
+ */
6
+ class RichTextEditor extends ConfigurableComponent {
7
+ /**
8
+ * @param {Element | null} $root - HTML element to use for rich text editor
9
+ * @param {RichTextEditorConfig} config
10
+ */
11
+ constructor($root, config = {}) {
12
+ super($root, config);
13
+ if (!RichTextEditor.isSupported()) {
14
+ return this;
15
+ }
16
+ const $textarea = this.$root.querySelector('.govuk-textarea');
17
+ if (!$textarea || !($textarea instanceof HTMLTextAreaElement)) {
18
+ return this;
19
+ }
20
+ this.$textarea = $textarea;
21
+ this.createToolbar();
22
+ this.hideDefault();
23
+ this.configureToolbar();
24
+ this.keys = {
25
+ left: 37,
26
+ right: 39,
27
+ up: 38,
28
+ down: 40
29
+ };
30
+ this.$content.addEventListener('input', this.onEditorInput.bind(this));
31
+ this.$root.querySelector('label').addEventListener('click', this.onLabelClick.bind(this));
32
+ this.$toolbar.addEventListener('keydown', this.onToolbarKeydown.bind(this));
4
33
  }
5
34
 
6
- this.options = options;
7
- this.options.toolbar = this.options.toolbar || {
8
- bold: false,
9
- italic: false,
10
- underline: false,
11
- bullets: true,
12
- numbers: true
13
- };
14
- this.textarea = this.options.textarea;
15
- this.container = $(this.textarea).parent();
16
-
17
- if (this.container.data('moj-rich-text-editor-initialised')) {
18
- return
35
+ /**
36
+ * @param {KeyboardEvent} event - Click event
37
+ */
38
+ onToolbarKeydown(event) {
39
+ let $focusableButton;
40
+ switch (event.keyCode) {
41
+ case this.keys.right:
42
+ case this.keys.down:
43
+ {
44
+ $focusableButton = this.$buttons.find(button => button.getAttribute('tabindex') === '0');
45
+ if ($focusableButton) {
46
+ const $nextButton = $focusableButton.nextElementSibling;
47
+ if ($nextButton && $nextButton instanceof HTMLButtonElement) {
48
+ $nextButton.focus();
49
+ $focusableButton.setAttribute('tabindex', '-1');
50
+ $nextButton.setAttribute('tabindex', '0');
51
+ }
52
+ }
53
+ break;
54
+ }
55
+ case this.keys.left:
56
+ case this.keys.up:
57
+ {
58
+ $focusableButton = this.$buttons.find(button => button.getAttribute('tabindex') === '0');
59
+ if ($focusableButton) {
60
+ const $previousButton = $focusableButton.previousElementSibling;
61
+ if ($previousButton && $previousButton instanceof HTMLButtonElement) {
62
+ $previousButton.focus();
63
+ $focusableButton.setAttribute('tabindex', '-1');
64
+ $previousButton.setAttribute('tabindex', '0');
65
+ }
66
+ }
67
+ break;
68
+ }
69
+ }
19
70
  }
20
-
21
- this.container.data('moj-rich-text-editor-initialised', true);
22
-
23
- this.createToolbar();
24
- this.hideDefault();
25
- this.configureToolbar();
26
- this.keys = {
27
- left: 37,
28
- right: 39,
29
- up: 38,
30
- down: 40
31
- };
32
- this.container.on(
33
- 'click',
34
- '.moj-rich-text-editor__toolbar-button',
35
- $.proxy(this, 'onButtonClick')
36
- );
37
- this.container
38
- .find('.moj-rich-text-editor__content')
39
- .on('input', $.proxy(this, 'onEditorInput'));
40
- this.container.find('label').on('click', $.proxy(this, 'onLabelClick'));
41
- this.toolbar.on('keydown', $.proxy(this, 'onToolbarKeydown'));
42
- }
43
-
44
- RichTextEditor.prototype.onToolbarKeydown = function (e) {
45
- let focusableButton;
46
- switch (e.keyCode) {
47
- case this.keys.right:
48
- case this.keys.down: {
49
- focusableButton = this.toolbar.find('button[tabindex=0]');
50
- const nextButton = focusableButton.next('button');
51
- if (nextButton[0]) {
52
- nextButton.focus();
53
- focusableButton.attr('tabindex', '-1');
54
- nextButton.attr('tabindex', '0');
55
- }
56
- break
71
+ getToolbarHtml() {
72
+ let html = '';
73
+ html += '<div class="moj-rich-text-editor__toolbar" role="toolbar">';
74
+ if (this.config.toolbar.bold) {
75
+ html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--bold" type="button" data-command="bold"><span class="govuk-visually-hidden">Bold</span></button>';
76
+ }
77
+ if (this.config.toolbar.italic) {
78
+ html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--italic" type="button" data-command="italic"><span class="govuk-visually-hidden">Italic</span></button>';
57
79
  }
58
- case this.keys.left:
59
- case this.keys.up: {
60
- focusableButton = this.toolbar.find('button[tabindex=0]');
61
- const previousButton = focusableButton.prev('button');
62
- if (previousButton[0]) {
63
- previousButton.focus();
64
- focusableButton.attr('tabindex', '-1');
65
- previousButton.attr('tabindex', '0');
66
- }
67
- break
80
+ if (this.config.toolbar.underline) {
81
+ html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--underline" type="button" data-command="underline"><span class="govuk-visually-hidden">Underline</span></button>';
68
82
  }
83
+ if (this.config.toolbar.bullets) {
84
+ html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--unordered-list" type="button" data-command="insertUnorderedList"><span class="govuk-visually-hidden">Unordered list</span></button>';
85
+ }
86
+ if (this.config.toolbar.numbers) {
87
+ html += '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--ordered-list" type="button" data-command="insertOrderedList"><span class="govuk-visually-hidden">Ordered list</span></button>';
88
+ }
89
+ html += '</div>';
90
+ return html;
69
91
  }
70
- };
71
-
72
- RichTextEditor.prototype.getToolbarHtml = function () {
73
- let html = '';
74
-
75
- html += '<div class="moj-rich-text-editor__toolbar" role="toolbar">';
76
-
77
- if (this.options.toolbar.bold) {
78
- html +=
79
- '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--bold" type="button" data-command="bold"><span class="govuk-visually-hidden">Bold</span></button>';
92
+ getEnhancedHtml() {
93
+ return `${this.getToolbarHtml()}<div class="govuk-textarea moj-rich-text-editor__content" contenteditable="true" spellcheck="false"></div>`;
80
94
  }
81
-
82
- if (this.options.toolbar.italic) {
83
- html +=
84
- '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--italic" type="button" data-command="italic"><span class="govuk-visually-hidden">Italic</span></button>';
95
+ hideDefault() {
96
+ this.$textarea.classList.add('govuk-visually-hidden');
97
+ this.$textarea.setAttribute('aria-hidden', 'true');
98
+ this.$textarea.setAttribute('tabindex', '-1');
85
99
  }
86
-
87
- if (this.options.toolbar.underline) {
88
- html +=
89
- '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--underline" type="button" data-command="underline"><span class="govuk-visually-hidden">Underline</span></button>';
100
+ createToolbar() {
101
+ this.$toolbar = document.createElement('div');
102
+ this.$toolbar.className = 'moj-rich-text-editor';
103
+ this.$toolbar.innerHTML = this.getEnhancedHtml();
104
+ this.$root.append(this.$toolbar);
105
+ this.$content = /** @type {HTMLElement} */
106
+ this.$root.querySelector('.moj-rich-text-editor__content');
107
+ this.$content.innerHTML = this.$textarea.value;
90
108
  }
91
-
92
- if (this.options.toolbar.bullets) {
93
- html +=
94
- '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--unordered-list" type="button" data-command="insertUnorderedList"><span class="govuk-visually-hidden">Unordered list</span></button>';
109
+ configureToolbar() {
110
+ this.$buttons = Array.from(/** @type {NodeListOf<HTMLButtonElement>} */
111
+ this.$root.querySelectorAll('.moj-rich-text-editor__toolbar-button'));
112
+ this.$buttons.forEach(($button, index) => {
113
+ $button.setAttribute('tabindex', !index ? '0' : '-1');
114
+ $button.addEventListener('click', this.onButtonClick.bind(this));
115
+ });
95
116
  }
96
117
 
97
- if (this.options.toolbar.numbers) {
98
- html +=
99
- '<button class="moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--ordered-list" type="button" data-command="insertOrderedList"><span class="govuk-visually-hidden">Ordered list</span></button>';
118
+ /**
119
+ * @param {MouseEvent} event - Click event
120
+ */
121
+ onButtonClick(event) {
122
+ if (!(event.currentTarget instanceof HTMLElement)) {
123
+ return;
124
+ }
125
+ document.execCommand(event.currentTarget.getAttribute('data-command'), false, undefined);
126
+ }
127
+ getContent() {
128
+ return this.$content.innerHTML;
129
+ }
130
+ onEditorInput() {
131
+ this.updateTextarea();
132
+ }
133
+ updateTextarea() {
134
+ document.execCommand('defaultParagraphSeparator', false, 'p');
135
+ this.$textarea.value = this.getContent();
100
136
  }
101
137
 
102
- html += '</div>';
103
- return html
104
- };
105
-
106
- RichTextEditor.prototype.getEnhancedHtml = function (val) {
107
- return `${this.getToolbarHtml()}<div class="govuk-textarea moj-rich-text-editor__content" contenteditable="true" spellcheck="false"></div>`
108
- };
109
-
110
- RichTextEditor.prototype.hideDefault = function () {
111
- this.textarea = this.container.find('textarea');
112
- this.textarea.addClass('govuk-visually-hidden');
113
- this.textarea.attr('aria-hidden', true);
114
- this.textarea.attr('tabindex', '-1');
115
- };
116
-
117
- RichTextEditor.prototype.createToolbar = function () {
118
- this.toolbar = document.createElement('div');
119
- this.toolbar.className = 'moj-rich-text-editor';
120
- this.toolbar.innerHTML = this.getEnhancedHtml();
121
- this.container.append(this.toolbar);
122
- this.toolbar = this.container.find('.moj-rich-text-editor__toolbar');
123
- this.container
124
- .find('.moj-rich-text-editor__content')
125
- .html(this.textarea.val());
126
- };
127
-
128
- RichTextEditor.prototype.configureToolbar = function () {
129
- this.buttons = this.container.find('.moj-rich-text-editor__toolbar-button');
130
- this.buttons.prop('tabindex', '-1');
131
- const firstTab = this.buttons.first();
132
- firstTab.prop('tabindex', '0');
133
- };
134
-
135
- RichTextEditor.prototype.onButtonClick = function (e) {
136
- document.execCommand($(e.currentTarget).data('command'), false, null);
137
- };
138
-
139
- RichTextEditor.prototype.getContent = function () {
140
- return this.container.find('.moj-rich-text-editor__content').html()
141
- };
142
-
143
- RichTextEditor.prototype.onEditorInput = function (e) {
144
- this.updateTextarea();
145
- };
138
+ /**
139
+ * @param {MouseEvent} event - Click event
140
+ */
141
+ onLabelClick(event) {
142
+ event.preventDefault();
143
+ this.$content.focus();
144
+ }
145
+ static isSupported() {
146
+ return 'contentEditable' in document.documentElement;
147
+ }
146
148
 
147
- RichTextEditor.prototype.updateTextarea = function () {
148
- document.execCommand('defaultParagraphSeparator', false, 'p');
149
- this.textarea.val(this.getContent());
150
- };
149
+ /**
150
+ * Name for the component used when initialising using data-module attributes.
151
+ */
152
+ }
151
153
 
152
- RichTextEditor.prototype.onLabelClick = function (e) {
153
- e.preventDefault();
154
- this.container.find('.moj-rich-text-editor__content').focus();
155
- };
154
+ /**
155
+ * Rich text editor config
156
+ *
157
+ * @typedef {object} RichTextEditorConfig
158
+ * @property {RichTextEditorToolbar} [toolbar] - Toolbar options
159
+ */
160
+
161
+ /**
162
+ * Rich text editor toolbar options
163
+ *
164
+ * @typedef {object} RichTextEditorToolbar
165
+ * @property {boolean} [bold] - Show the bold button
166
+ * @property {boolean} [italic] - Show the italic button
167
+ * @property {boolean} [underline] - Show the underline button
168
+ * @property {boolean} [bullets] - Show the bullets button
169
+ * @property {boolean} [numbers] - Show the numbers button
170
+ */
171
+
172
+ /**
173
+ * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
174
+ */
175
+ RichTextEditor.moduleName = 'moj-rich-text-editor';
176
+ /**
177
+ * Rich text editor config
178
+ *
179
+ * @type {RichTextEditorConfig}
180
+ */
181
+ RichTextEditor.defaults = Object.freeze({
182
+ toolbar: {
183
+ bold: false,
184
+ italic: false,
185
+ underline: false,
186
+ bullets: true,
187
+ numbers: true
188
+ }
189
+ });
190
+ /**
191
+ * Rich text editor config schema
192
+ *
193
+ * @satisfies {Schema<RichTextEditorConfig>}
194
+ */
195
+ RichTextEditor.schema = Object.freeze(/** @type {const} */{
196
+ properties: {
197
+ toolbar: {
198
+ type: 'object'
199
+ }
200
+ }
201
+ });
156
202
 
157
203
  export { RichTextEditor };
158
204
  //# sourceMappingURL=rich-text-editor.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"rich-text-editor.mjs","sources":["../../../../src/moj/components/rich-text-editor/rich-text-editor.mjs"],"sourcesContent":["import $ from 'jquery'\n\nexport function RichTextEditor(options) {\n if (!('contentEditable' in document.documentElement)) {\n return\n }\n\n this.options = options\n this.options.toolbar = this.options.toolbar || {\n bold: false,\n italic: false,\n underline: false,\n bullets: true,\n numbers: true\n }\n this.textarea = this.options.textarea\n this.container = $(this.textarea).parent()\n\n if (this.container.data('moj-rich-text-editor-initialised')) {\n return\n }\n\n this.container.data('moj-rich-text-editor-initialised', true)\n\n this.createToolbar()\n this.hideDefault()\n this.configureToolbar()\n this.keys = {\n left: 37,\n right: 39,\n up: 38,\n down: 40\n }\n this.container.on(\n 'click',\n '.moj-rich-text-editor__toolbar-button',\n $.proxy(this, 'onButtonClick')\n )\n this.container\n .find('.moj-rich-text-editor__content')\n .on('input', $.proxy(this, 'onEditorInput'))\n this.container.find('label').on('click', $.proxy(this, 'onLabelClick'))\n this.toolbar.on('keydown', $.proxy(this, 'onToolbarKeydown'))\n}\n\nRichTextEditor.prototype.onToolbarKeydown = function (e) {\n let focusableButton\n switch (e.keyCode) {\n case this.keys.right:\n case this.keys.down: {\n focusableButton = this.toolbar.find('button[tabindex=0]')\n const nextButton = focusableButton.next('button')\n if (nextButton[0]) {\n nextButton.focus()\n focusableButton.attr('tabindex', '-1')\n nextButton.attr('tabindex', '0')\n }\n break\n }\n case this.keys.left:\n case this.keys.up: {\n focusableButton = this.toolbar.find('button[tabindex=0]')\n const previousButton = focusableButton.prev('button')\n if (previousButton[0]) {\n previousButton.focus()\n focusableButton.attr('tabindex', '-1')\n previousButton.attr('tabindex', '0')\n }\n break\n }\n }\n}\n\nRichTextEditor.prototype.getToolbarHtml = function () {\n let html = ''\n\n html += '<div class=\"moj-rich-text-editor__toolbar\" role=\"toolbar\">'\n\n if (this.options.toolbar.bold) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--bold\" type=\"button\" data-command=\"bold\"><span class=\"govuk-visually-hidden\">Bold</span></button>'\n }\n\n if (this.options.toolbar.italic) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--italic\" type=\"button\" data-command=\"italic\"><span class=\"govuk-visually-hidden\">Italic</span></button>'\n }\n\n if (this.options.toolbar.underline) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--underline\" type=\"button\" data-command=\"underline\"><span class=\"govuk-visually-hidden\">Underline</span></button>'\n }\n\n if (this.options.toolbar.bullets) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--unordered-list\" type=\"button\" data-command=\"insertUnorderedList\"><span class=\"govuk-visually-hidden\">Unordered list</span></button>'\n }\n\n if (this.options.toolbar.numbers) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--ordered-list\" type=\"button\" data-command=\"insertOrderedList\"><span class=\"govuk-visually-hidden\">Ordered list</span></button>'\n }\n\n html += '</div>'\n return html\n}\n\nRichTextEditor.prototype.getEnhancedHtml = function (val) {\n return `${this.getToolbarHtml()}<div class=\"govuk-textarea moj-rich-text-editor__content\" contenteditable=\"true\" spellcheck=\"false\"></div>`\n}\n\nRichTextEditor.prototype.hideDefault = function () {\n this.textarea = this.container.find('textarea')\n this.textarea.addClass('govuk-visually-hidden')\n this.textarea.attr('aria-hidden', true)\n this.textarea.attr('tabindex', '-1')\n}\n\nRichTextEditor.prototype.createToolbar = function () {\n this.toolbar = document.createElement('div')\n this.toolbar.className = 'moj-rich-text-editor'\n this.toolbar.innerHTML = this.getEnhancedHtml()\n this.container.append(this.toolbar)\n this.toolbar = this.container.find('.moj-rich-text-editor__toolbar')\n this.container\n .find('.moj-rich-text-editor__content')\n .html(this.textarea.val())\n}\n\nRichTextEditor.prototype.configureToolbar = function () {\n this.buttons = this.container.find('.moj-rich-text-editor__toolbar-button')\n this.buttons.prop('tabindex', '-1')\n const firstTab = this.buttons.first()\n firstTab.prop('tabindex', '0')\n}\n\nRichTextEditor.prototype.onButtonClick = function (e) {\n document.execCommand($(e.currentTarget).data('command'), false, null)\n}\n\nRichTextEditor.prototype.getContent = function () {\n return this.container.find('.moj-rich-text-editor__content').html()\n}\n\nRichTextEditor.prototype.onEditorInput = function (e) {\n this.updateTextarea()\n}\n\nRichTextEditor.prototype.updateTextarea = function () {\n document.execCommand('defaultParagraphSeparator', false, 'p')\n this.textarea.val(this.getContent())\n}\n\nRichTextEditor.prototype.onLabelClick = function (e) {\n e.preventDefault()\n this.container.find('.moj-rich-text-editor__content').focus()\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rich-text-editor.mjs","sources":["../../../../src/moj/components/rich-text-editor/rich-text-editor.mjs"],"sourcesContent":["import { ConfigurableComponent } from 'govuk-frontend'\n\n/**\n * @augments {ConfigurableComponent<RichTextEditorConfig>}\n */\nexport class RichTextEditor extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for rich text editor\n * @param {RichTextEditorConfig} config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n if (!RichTextEditor.isSupported()) {\n return this\n }\n\n const $textarea = this.$root.querySelector('.govuk-textarea')\n if (!$textarea || !($textarea instanceof HTMLTextAreaElement)) {\n return this\n }\n\n this.$textarea = $textarea\n\n this.createToolbar()\n this.hideDefault()\n this.configureToolbar()\n\n this.keys = {\n left: 37,\n right: 39,\n up: 38,\n down: 40\n }\n\n this.$content.addEventListener('input', this.onEditorInput.bind(this))\n\n this.$root\n .querySelector('label')\n .addEventListener('click', this.onLabelClick.bind(this))\n\n this.$toolbar.addEventListener('keydown', this.onToolbarKeydown.bind(this))\n }\n\n /**\n * @param {KeyboardEvent} event - Click event\n */\n onToolbarKeydown(event) {\n let $focusableButton\n switch (event.keyCode) {\n case this.keys.right:\n case this.keys.down: {\n $focusableButton = this.$buttons.find(\n (button) => button.getAttribute('tabindex') === '0'\n )\n\n if ($focusableButton) {\n const $nextButton = $focusableButton.nextElementSibling\n\n if ($nextButton && $nextButton instanceof HTMLButtonElement) {\n $nextButton.focus()\n $focusableButton.setAttribute('tabindex', '-1')\n $nextButton.setAttribute('tabindex', '0')\n }\n }\n\n break\n }\n\n case this.keys.left:\n case this.keys.up: {\n $focusableButton = this.$buttons.find(\n (button) => button.getAttribute('tabindex') === '0'\n )\n\n if ($focusableButton) {\n const $previousButton = $focusableButton.previousElementSibling\n\n if ($previousButton && $previousButton instanceof HTMLButtonElement) {\n $previousButton.focus()\n $focusableButton.setAttribute('tabindex', '-1')\n $previousButton.setAttribute('tabindex', '0')\n }\n }\n\n break\n }\n }\n }\n\n getToolbarHtml() {\n let html = ''\n\n html += '<div class=\"moj-rich-text-editor__toolbar\" role=\"toolbar\">'\n\n if (this.config.toolbar.bold) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--bold\" type=\"button\" data-command=\"bold\"><span class=\"govuk-visually-hidden\">Bold</span></button>'\n }\n\n if (this.config.toolbar.italic) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--italic\" type=\"button\" data-command=\"italic\"><span class=\"govuk-visually-hidden\">Italic</span></button>'\n }\n\n if (this.config.toolbar.underline) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--underline\" type=\"button\" data-command=\"underline\"><span class=\"govuk-visually-hidden\">Underline</span></button>'\n }\n\n if (this.config.toolbar.bullets) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--unordered-list\" type=\"button\" data-command=\"insertUnorderedList\"><span class=\"govuk-visually-hidden\">Unordered list</span></button>'\n }\n\n if (this.config.toolbar.numbers) {\n html +=\n '<button class=\"moj-rich-text-editor__toolbar-button moj-rich-text-editor__toolbar-button--ordered-list\" type=\"button\" data-command=\"insertOrderedList\"><span class=\"govuk-visually-hidden\">Ordered list</span></button>'\n }\n\n html += '</div>'\n return html\n }\n\n getEnhancedHtml() {\n return `${this.getToolbarHtml()}<div class=\"govuk-textarea moj-rich-text-editor__content\" contenteditable=\"true\" spellcheck=\"false\"></div>`\n }\n\n hideDefault() {\n this.$textarea.classList.add('govuk-visually-hidden')\n this.$textarea.setAttribute('aria-hidden', 'true')\n this.$textarea.setAttribute('tabindex', '-1')\n }\n\n createToolbar() {\n this.$toolbar = document.createElement('div')\n this.$toolbar.className = 'moj-rich-text-editor'\n this.$toolbar.innerHTML = this.getEnhancedHtml()\n this.$root.append(this.$toolbar)\n\n this.$content = /** @type {HTMLElement} */ (\n this.$root.querySelector('.moj-rich-text-editor__content')\n )\n\n this.$content.innerHTML = this.$textarea.value\n }\n\n configureToolbar() {\n this.$buttons = Array.from(\n /** @type {NodeListOf<HTMLButtonElement>} */\n (this.$root.querySelectorAll('.moj-rich-text-editor__toolbar-button'))\n )\n\n this.$buttons.forEach(($button, index) => {\n $button.setAttribute('tabindex', !index ? '0' : '-1')\n $button.addEventListener('click', this.onButtonClick.bind(this))\n })\n }\n\n /**\n * @param {MouseEvent} event - Click event\n */\n onButtonClick(event) {\n if (!(event.currentTarget instanceof HTMLElement)) {\n return\n }\n\n document.execCommand(\n event.currentTarget.getAttribute('data-command'),\n false,\n undefined\n )\n }\n\n getContent() {\n return this.$content.innerHTML\n }\n\n onEditorInput() {\n this.updateTextarea()\n }\n\n updateTextarea() {\n document.execCommand('defaultParagraphSeparator', false, 'p')\n this.$textarea.value = this.getContent()\n }\n\n /**\n * @param {MouseEvent} event - Click event\n */\n onLabelClick(event) {\n event.preventDefault()\n this.$content.focus()\n }\n\n static isSupported() {\n return 'contentEditable' in document.documentElement\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-rich-text-editor'\n\n /**\n * Rich text editor config\n *\n * @type {RichTextEditorConfig}\n */\n static defaults = Object.freeze({\n toolbar: {\n bold: false,\n italic: false,\n underline: false,\n bullets: true,\n numbers: true\n }\n })\n\n /**\n * Rich text editor config schema\n *\n * @satisfies {Schema<RichTextEditorConfig>}\n */\n static schema = Object.freeze(\n /** @type {const} */ ({\n properties: {\n toolbar: { type: 'object' }\n }\n })\n )\n}\n\n/**\n * Rich text editor config\n *\n * @typedef {object} RichTextEditorConfig\n * @property {RichTextEditorToolbar} [toolbar] - Toolbar options\n */\n\n/**\n * Rich text editor toolbar options\n *\n * @typedef {object} RichTextEditorToolbar\n * @property {boolean} [bold] - Show the bold button\n * @property {boolean} [italic] - Show the italic button\n * @property {boolean} [underline] - Show the underline button\n * @property {boolean} [bullets] - Show the bullets button\n * @property {boolean} [numbers] - Show the numbers button\n */\n\n/**\n * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'\n */\n"],"names":["RichTextEditor","ConfigurableComponent","constructor","$root","config","isSupported","$textarea","querySelector","HTMLTextAreaElement","createToolbar","hideDefault","configureToolbar","keys","left","right","up","down","$content","addEventListener","onEditorInput","bind","onLabelClick","$toolbar","onToolbarKeydown","event","$focusableButton","keyCode","$buttons","find","button","getAttribute","$nextButton","nextElementSibling","HTMLButtonElement","focus","setAttribute","$previousButton","previousElementSibling","getToolbarHtml","html","toolbar","bold","italic","underline","bullets","numbers","getEnhancedHtml","classList","add","document","createElement","className","innerHTML","append","value","Array","from","querySelectorAll","forEach","$button","index","onButtonClick","currentTarget","HTMLElement","execCommand","undefined","getContent","updateTextarea","preventDefault","documentElement","moduleName","defaults","Object","freeze","schema","properties","type"],"mappings":"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"}
@@ -44,3 +44,5 @@
44
44
  padding: 0 !important;
45
45
  }
46
46
  }
47
+
48
+ /*# sourceMappingURL=_search.scss.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/moj/components/search/_search.scss"],"names":[],"mappings":"AAAA,uCAAuC;;AAEvC;EACE,YAAY,EAAE,UAAU;AAC1B;;AAEA;EACE,qBAAqB;EACrB,aAAa;AACf;;AAEA;EACE,qBAAqB;EACrB,OAAO;EACP,gBAAgB;EAChB,mBAAmB;AACrB;;AAEA;;EAEE,gBAAgB;AAClB;;AAEA;EACE,kBAAkB;EAClB,UAAU;AACZ;;AAEA;EACE,qBAAqB;EACrB,kBAAkB;EAClB,SAAS,EAAE,8DAA8D;EACzE,WAAW;EACX,gBAAgB;EAChB,6BAA6B;EAC7B,sBAAsB;AACxB;;AAEA;EACE,sDAAsD;EACtD,sCAAsC;EACtC;IACE,sDAAsD;IACtD,qBAAqB;EACvB;AACF","file":"_search.scss","sourcesContent":["@use \"../../vendor/govuk-frontend\" as *;\n\n.moj-search {\n font-size: 0; // Fallback\n}\n\n.moj-search form {\n align-items: flex-end;\n display: flex;\n}\n\n.moj-search .govuk-form-group {\n display: inline-block;\n flex: 1;\n margin-bottom: 0;\n vertical-align: top;\n}\n\n.moj-search__label,\n.moj-search__hint {\n text-align: left;\n}\n\n.moj-search__input:focus {\n position: relative;\n z-index: 1;\n}\n\n.moj-search__button {\n display: inline-block;\n position: relative;\n top: -2px; // Override default gov properties due to active pixel movement\n width: auto;\n margin-bottom: 0;\n margin-left: govuk-spacing(2);\n vertical-align: bottom;\n}\n\n.moj-search--inline {\n // stylelint-disable-next-line declaration-no-important\n padding: govuk-spacing(2) 0 !important;\n @include govuk-media-query($from: desktop) {\n // stylelint-disable-next-line declaration-no-important\n padding: 0 !important;\n }\n}\n"]}
@@ -75,3 +75,5 @@
75
75
  max-width: 450px;
76
76
  }
77
77
  }
78
+
79
+ /*# sourceMappingURL=_search-toggle.scss.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/moj/components/search-toggle/_search-toggle.scss"],"names":[],"mappings":"AAAA,uCAAuC;;AAEvC;EACE,qBAAqB;EACrB,iBAAiB;EACjB,gBAAgB;EAChB,oBAAoB;EACpB,eAAe;EACf,YAAY;EACZ,yBAAyB;EACzB,6BAA6B;EAC7B,eAAe;EACf,mCAAmC;EACnC,wBAAwB;EACxB,gBAAgB;EAChB,6CAA6C;;EAE7C;IACE,qBAAqB;IACrB,WAAW;IACX,YAAY;IACZ,6BAA6B;IAC7B,kBAAkB;IAClB,sBAAsB;;IAEtB;MACE,gBAAgB;IAClB;EACF;;EAEA;IACE,kBAAkB;IAClB,UAAU;IACV,aAAa;IACb,+BAA+B;IAC/B,qCAAqC;IACrC;;oCAEgC;EAClC;AACF;;AAEA;EACE,yBAAyB;;EAEzB;IACE,sDAAsD;IACtD,2BAA2B;IAC3B,sDAAsD;IACtD,0BAA0B;EAC5B;AACF;;AAEA,YAAY;AACZ;EACE;IACE,sDAAsD;IACtD,yBAAyB;EAC3B;AACF;;AAEA;EACE,kBAAkB;AACpB;;AAEA;EACE,4CAA4C;;EAE5C;IACE,kBAAkB;IAClB,WAAW;IACX,SAAS,EAAE,mBAAmB;IAC9B,YAAY;IACZ,YAAY;IACZ,gBAAgB;EAClB;AACF","file":"_search-toggle.scss","sourcesContent":["@use \"../../vendor/govuk-frontend\" as *;\n\n.moj-search-toggle__button {\n display: inline-block;\n padding-top: 12px;\n padding-right: 0;\n padding-bottom: 13px;\n padding-left: 0;\n border: none;\n color: $govuk-link-colour;\n background-color: transparent;\n cursor: pointer;\n -webkit-font-smoothing: antialiased;\n -webkit-appearance: none;\n appearance: none;\n @include govuk-font($size: 19, $weight: bold);\n\n &__icon {\n display: inline-block;\n width: 20px;\n height: 20px;\n margin-left: govuk-spacing(2);\n fill: currentcolor;\n vertical-align: middle;\n\n @media screen and (forced-colors: active) {\n fill: windowText;\n }\n }\n\n &:focus {\n position: relative;\n z-index: 1;\n outline: none;\n color: $govuk-focus-text-colour;\n background-color: $govuk-focus-colour;\n box-shadow:\n 0 -2px $govuk-focus-colour,\n 0 4px $govuk-focus-text-colour;\n }\n}\n\n.moj-search--toggle {\n padding: govuk-spacing(3);\n\n @include govuk-media-query($until: desktop) {\n // stylelint-disable-next-line declaration-no-important\n padding-right: 0 !important;\n // stylelint-disable-next-line declaration-no-important\n padding-left: 0 !important;\n }\n}\n\n// JS enabled\n.js-enabled .moj-search--toggle {\n @include govuk-media-query($until: desktop) {\n // stylelint-disable-next-line declaration-no-important\n padding-top: 0 !important;\n }\n}\n\n.js-enabled .moj-search-toggle {\n position: relative;\n}\n\n.js-enabled .moj-search-toggle__search {\n background-color: govuk-colour(\"light-grey\");\n\n @include govuk-media-query($from: desktop) {\n position: absolute;\n z-index: 10;\n top: 50px; // Height of nav bar\n right: -15px;\n width: 450px;\n max-width: 450px;\n }\n}\n"]}
@@ -0,0 +1,122 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('govuk-frontend')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'govuk-frontend'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MOJFrontend = global.MOJFrontend || {}, global.GOVUKFrontend));
5
+ })(this, (function (exports, govukFrontend) { 'use strict';
6
+
7
+ /**
8
+ * @augments {ConfigurableComponent<SearchToggleConfig>}
9
+ */
10
+ class SearchToggle extends govukFrontend.ConfigurableComponent {
11
+ /**
12
+ * @param {Element | null} $root - HTML element to use for search toggle
13
+ * @param {SearchToggleConfig} [config] - Search toggle config
14
+ */
15
+ constructor($root, config = {}) {
16
+ var _this$config$searchCo, _this$config$toggleBu;
17
+ super($root, config);
18
+ const $searchContainer = (_this$config$searchCo = this.config.searchContainer.element) != null ? _this$config$searchCo : this.$root.querySelector(this.config.searchContainer.selector);
19
+ const $toggleButtonContainer = (_this$config$toggleBu = this.config.toggleButtonContainer.element) != null ? _this$config$toggleBu : this.$root.querySelector(this.config.toggleButtonContainer.selector);
20
+ if (!$searchContainer || !$toggleButtonContainer || !($searchContainer instanceof HTMLElement) || !($toggleButtonContainer instanceof HTMLElement)) {
21
+ return this;
22
+ }
23
+ this.$searchContainer = $searchContainer;
24
+ this.$toggleButtonContainer = $toggleButtonContainer;
25
+ const svg = '<svg viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="moj-search-toggle__button__icon"><path d="M7.433,12.5790048 C6.06762625,12.5808611 4.75763941,12.0392925 3.79217348,11.0738265 C2.82670755,10.1083606 2.28513891,8.79837375 2.28699522,7.433 C2.28513891,6.06762625 2.82670755,4.75763941 3.79217348,3.79217348 C4.75763941,2.82670755 6.06762625,2.28513891 7.433,2.28699522 C8.79837375,2.28513891 10.1083606,2.82670755 11.0738265,3.79217348 C12.0392925,4.75763941 12.5808611,6.06762625 12.5790048,7.433 C12.5808611,8.79837375 12.0392925,10.1083606 11.0738265,11.0738265 C10.1083606,12.0392925 8.79837375,12.5808611 7.433,12.5790048 L7.433,12.5790048 Z M14.293,12.579 L13.391,12.579 L13.071,12.269 C14.2300759,10.9245158 14.8671539,9.20813198 14.866,7.433 C14.866,3.32786745 11.5381325,-1.65045755e-15 7.433,-1.65045755e-15 C3.32786745,-1.65045755e-15 -1.65045755e-15,3.32786745 -1.65045755e-15,7.433 C-1.65045755e-15,11.5381325 3.32786745,14.866 7.433,14.866 C9.208604,14.8671159 10.9253982,14.2296624 12.27,13.07 L12.579,13.39 L12.579,14.294 L18.296,20 L20,18.296 L14.294,12.579 L14.293,12.579 Z"></path></svg>';
26
+ this.$toggleButton = document.createElement('button');
27
+ this.$toggleButton.setAttribute('class', 'moj-search-toggle__button');
28
+ this.$toggleButton.setAttribute('type', 'button');
29
+ this.$toggleButton.setAttribute('aria-haspopup', 'true');
30
+ this.$toggleButton.setAttribute('aria-expanded', 'false');
31
+ this.$toggleButton.innerHTML = `${this.config.toggleButton.text} ${svg}`;
32
+ this.$toggleButton.addEventListener('click', this.onToggleButtonClick.bind(this));
33
+ this.$toggleButtonContainer.append(this.$toggleButton);
34
+ document.addEventListener('click', this.onDocumentClick.bind(this));
35
+ document.addEventListener('focusin', this.onDocumentClick.bind(this));
36
+ }
37
+ showMenu() {
38
+ this.$toggleButton.setAttribute('aria-expanded', 'true');
39
+ this.$searchContainer.classList.remove('moj-js-hidden');
40
+ this.$searchContainer.querySelector('input').focus();
41
+ }
42
+ hideMenu() {
43
+ this.$searchContainer.classList.add('moj-js-hidden');
44
+ this.$toggleButton.setAttribute('aria-expanded', 'false');
45
+ }
46
+ onToggleButtonClick() {
47
+ if (this.$toggleButton.getAttribute('aria-expanded') === 'false') {
48
+ this.showMenu();
49
+ } else {
50
+ this.hideMenu();
51
+ }
52
+ }
53
+
54
+ /**
55
+ * @param {MouseEvent | FocusEvent} event
56
+ */
57
+ onDocumentClick(event) {
58
+ if (event.target instanceof Node && !this.$toggleButtonContainer.contains(event.target) && !this.$searchContainer.contains(event.target)) {
59
+ this.hideMenu();
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Name for the component used when initialising using data-module attributes.
65
+ */
66
+ }
67
+
68
+ /**
69
+ * @typedef {object} SearchToggleConfig
70
+ * @property {object} [searchContainer] - Search config
71
+ * @property {string} [searchContainer.selector] - Selector for search container
72
+ * @property {Element | null} [searchContainer.element] - HTML element for search container
73
+ * @property {object} [toggleButton] - Toggle button config
74
+ * @property {string} [toggleButton.text] - Text for toggle button
75
+ * @property {object} [toggleButtonContainer] - Toggle button container config
76
+ * @property {string} [toggleButtonContainer.selector] - Selector for toggle button container
77
+ * @property {Element | null} [toggleButtonContainer.element] - HTML element for toggle button container
78
+ */
79
+
80
+ /**
81
+ * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
82
+ */
83
+ SearchToggle.moduleName = 'moj-search-toggle';
84
+ /**
85
+ * Search toggle config
86
+ *
87
+ * @type {SearchToggleConfig}
88
+ */
89
+ SearchToggle.defaults = Object.freeze({
90
+ searchContainer: {
91
+ selector: '.moj-search'
92
+ },
93
+ toggleButton: {
94
+ text: 'Search'
95
+ },
96
+ toggleButtonContainer: {
97
+ selector: '.moj-search-toggle__toggle'
98
+ }
99
+ });
100
+ /**
101
+ * Search toggle config schema
102
+ *
103
+ * @satisfies {Schema<SearchToggleConfig>}
104
+ */
105
+ SearchToggle.schema = Object.freeze(/** @type {const} */{
106
+ properties: {
107
+ searchContainer: {
108
+ type: 'object'
109
+ },
110
+ toggleButton: {
111
+ type: 'object'
112
+ },
113
+ toggleButtonContainer: {
114
+ type: 'object'
115
+ }
116
+ }
117
+ });
118
+
119
+ exports.SearchToggle = SearchToggle;
120
+
121
+ }));
122
+ //# sourceMappingURL=search-toggle.bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-toggle.bundle.js","sources":["../../../../src/moj/components/search-toggle/search-toggle.mjs"],"sourcesContent":["import { ConfigurableComponent } from 'govuk-frontend'\n\n/**\n * @augments {ConfigurableComponent<SearchToggleConfig>}\n */\nexport class SearchToggle extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for search toggle\n * @param {SearchToggleConfig} [config] - Search toggle config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n const $searchContainer =\n this.config.searchContainer.element ??\n this.$root.querySelector(this.config.searchContainer.selector)\n\n const $toggleButtonContainer =\n this.config.toggleButtonContainer.element ??\n this.$root.querySelector(this.config.toggleButtonContainer.selector)\n\n if (\n !$searchContainer ||\n !$toggleButtonContainer ||\n !($searchContainer instanceof HTMLElement) ||\n !($toggleButtonContainer instanceof HTMLElement)\n ) {\n return this\n }\n\n this.$searchContainer = $searchContainer\n this.$toggleButtonContainer = $toggleButtonContainer\n\n const svg =\n '<svg viewBox=\"0 0 20 20\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" class=\"moj-search-toggle__button__icon\"><path d=\"M7.433,12.5790048 C6.06762625,12.5808611 4.75763941,12.0392925 3.79217348,11.0738265 C2.82670755,10.1083606 2.28513891,8.79837375 2.28699522,7.433 C2.28513891,6.06762625 2.82670755,4.75763941 3.79217348,3.79217348 C4.75763941,2.82670755 6.06762625,2.28513891 7.433,2.28699522 C8.79837375,2.28513891 10.1083606,2.82670755 11.0738265,3.79217348 C12.0392925,4.75763941 12.5808611,6.06762625 12.5790048,7.433 C12.5808611,8.79837375 12.0392925,10.1083606 11.0738265,11.0738265 C10.1083606,12.0392925 8.79837375,12.5808611 7.433,12.5790048 L7.433,12.5790048 Z M14.293,12.579 L13.391,12.579 L13.071,12.269 C14.2300759,10.9245158 14.8671539,9.20813198 14.866,7.433 C14.866,3.32786745 11.5381325,-1.65045755e-15 7.433,-1.65045755e-15 C3.32786745,-1.65045755e-15 -1.65045755e-15,3.32786745 -1.65045755e-15,7.433 C-1.65045755e-15,11.5381325 3.32786745,14.866 7.433,14.866 C9.208604,14.8671159 10.9253982,14.2296624 12.27,13.07 L12.579,13.39 L12.579,14.294 L18.296,20 L20,18.296 L14.294,12.579 L14.293,12.579 Z\"></path></svg>'\n\n this.$toggleButton = document.createElement('button')\n this.$toggleButton.setAttribute('class', 'moj-search-toggle__button')\n this.$toggleButton.setAttribute('type', 'button')\n this.$toggleButton.setAttribute('aria-haspopup', 'true')\n this.$toggleButton.setAttribute('aria-expanded', 'false')\n this.$toggleButton.innerHTML = `${this.config.toggleButton.text} ${svg}`\n\n this.$toggleButton.addEventListener(\n 'click',\n this.onToggleButtonClick.bind(this)\n )\n\n this.$toggleButtonContainer.append(this.$toggleButton)\n\n document.addEventListener('click', this.onDocumentClick.bind(this))\n document.addEventListener('focusin', this.onDocumentClick.bind(this))\n }\n\n showMenu() {\n this.$toggleButton.setAttribute('aria-expanded', 'true')\n this.$searchContainer.classList.remove('moj-js-hidden')\n this.$searchContainer.querySelector('input').focus()\n }\n\n hideMenu() {\n this.$searchContainer.classList.add('moj-js-hidden')\n this.$toggleButton.setAttribute('aria-expanded', 'false')\n }\n\n onToggleButtonClick() {\n if (this.$toggleButton.getAttribute('aria-expanded') === 'false') {\n this.showMenu()\n } else {\n this.hideMenu()\n }\n }\n\n /**\n * @param {MouseEvent | FocusEvent} event\n */\n onDocumentClick(event) {\n if (\n event.target instanceof Node &&\n !this.$toggleButtonContainer.contains(event.target) &&\n !this.$searchContainer.contains(event.target)\n ) {\n this.hideMenu()\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-search-toggle'\n\n /**\n * Search toggle config\n *\n * @type {SearchToggleConfig}\n */\n static defaults = Object.freeze({\n searchContainer: {\n selector: '.moj-search'\n },\n toggleButton: {\n text: 'Search'\n },\n toggleButtonContainer: {\n selector: '.moj-search-toggle__toggle'\n }\n })\n\n /**\n * Search toggle config schema\n *\n * @satisfies {Schema<SearchToggleConfig>}\n */\n static schema = Object.freeze(\n /** @type {const} */ ({\n properties: {\n searchContainer: { type: 'object' },\n toggleButton: { type: 'object' },\n toggleButtonContainer: { type: 'object' }\n }\n })\n )\n}\n\n/**\n * @typedef {object} SearchToggleConfig\n * @property {object} [searchContainer] - Search config\n * @property {string} [searchContainer.selector] - Selector for search container\n * @property {Element | null} [searchContainer.element] - HTML element for search container\n * @property {object} [toggleButton] - Toggle button config\n * @property {string} [toggleButton.text] - Text for toggle button\n * @property {object} [toggleButtonContainer] - Toggle button container config\n * @property {string} [toggleButtonContainer.selector] - Selector for toggle button container\n * @property {Element | null} [toggleButtonContainer.element] - HTML element for toggle button container\n */\n\n/**\n * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'\n */\n"],"names":["SearchToggle","ConfigurableComponent","constructor","$root","config","_this$config$searchCo","_this$config$toggleBu","$searchContainer","searchContainer","element","querySelector","selector","$toggleButtonContainer","toggleButtonContainer","HTMLElement","svg","$toggleButton","document","createElement","setAttribute","innerHTML","toggleButton","text","addEventListener","onToggleButtonClick","bind","append","onDocumentClick","showMenu","classList","remove","focus","hideMenu","add","getAttribute","event","target","Node","contains","moduleName","defaults","Object","freeze","schema","properties","type"],"mappings":";;;;;;EAEA;EACA;EACA;EACO,MAAMA,YAAY,SAASC,mCAAqB,CAAC;EACtD;EACF;EACA;EACA;EACEC,EAAAA,WAAWA,CAACC,KAAK,EAAEC,MAAM,GAAG,EAAE,EAAE;MAAA,IAAAC,qBAAA,EAAAC,qBAAA;EAC9B,IAAA,KAAK,CAACH,KAAK,EAAEC,MAAM,CAAC;MAEpB,MAAMG,gBAAgB,GAAAF,CAAAA,qBAAA,GACpB,IAAI,CAACD,MAAM,CAACI,eAAe,CAACC,OAAO,KAAAJ,IAAAA,GAAAA,qBAAA,GACnC,IAAI,CAACF,KAAK,CAACO,aAAa,CAAC,IAAI,CAACN,MAAM,CAACI,eAAe,CAACG,QAAQ,CAAC;MAEhE,MAAMC,sBAAsB,GAAAN,CAAAA,qBAAA,GAC1B,IAAI,CAACF,MAAM,CAACS,qBAAqB,CAACJ,OAAO,KAAAH,IAAAA,GAAAA,qBAAA,GACzC,IAAI,CAACH,KAAK,CAACO,aAAa,CAAC,IAAI,CAACN,MAAM,CAACS,qBAAqB,CAACF,QAAQ,CAAC;EAEtE,IAAA,IACE,CAACJ,gBAAgB,IACjB,CAACK,sBAAsB,IACvB,EAAEL,gBAAgB,YAAYO,WAAW,CAAC,IAC1C,EAAEF,sBAAsB,YAAYE,WAAW,CAAC,EAChD;EACA,MAAA,OAAO,IAAI;EACb;MAEA,IAAI,CAACP,gBAAgB,GAAGA,gBAAgB;MACxC,IAAI,CAACK,sBAAsB,GAAGA,sBAAsB;MAEpD,MAAMG,GAAG,GACP,6pCAA6pC;MAE/pC,IAAI,CAACC,aAAa,GAAGC,QAAQ,CAACC,aAAa,CAAC,QAAQ,CAAC;MACrD,IAAI,CAACF,aAAa,CAACG,YAAY,CAAC,OAAO,EAAE,2BAA2B,CAAC;MACrE,IAAI,CAACH,aAAa,CAACG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;MACjD,IAAI,CAACH,aAAa,CAACG,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC;MACxD,IAAI,CAACH,aAAa,CAACG,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC;EACzD,IAAA,IAAI,CAACH,aAAa,CAACI,SAAS,GAAG,CAAG,EAAA,IAAI,CAAChB,MAAM,CAACiB,YAAY,CAACC,IAAI,CAAA,CAAA,EAAIP,GAAG,CAAE,CAAA;EAExE,IAAA,IAAI,CAACC,aAAa,CAACO,gBAAgB,CACjC,OAAO,EACP,IAAI,CAACC,mBAAmB,CAACC,IAAI,CAAC,IAAI,CACpC,CAAC;MAED,IAAI,CAACb,sBAAsB,CAACc,MAAM,CAAC,IAAI,CAACV,aAAa,CAAC;EAEtDC,IAAAA,QAAQ,CAACM,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACI,eAAe,CAACF,IAAI,CAAC,IAAI,CAAC,CAAC;EACnER,IAAAA,QAAQ,CAACM,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAACI,eAAe,CAACF,IAAI,CAAC,IAAI,CAAC,CAAC;EACvE;EAEAG,EAAAA,QAAQA,GAAG;MACT,IAAI,CAACZ,aAAa,CAACG,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC;MACxD,IAAI,CAACZ,gBAAgB,CAACsB,SAAS,CAACC,MAAM,CAAC,eAAe,CAAC;MACvD,IAAI,CAACvB,gBAAgB,CAACG,aAAa,CAAC,OAAO,CAAC,CAACqB,KAAK,EAAE;EACtD;EAEAC,EAAAA,QAAQA,GAAG;MACT,IAAI,CAACzB,gBAAgB,CAACsB,SAAS,CAACI,GAAG,CAAC,eAAe,CAAC;MACpD,IAAI,CAACjB,aAAa,CAACG,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC;EAC3D;EAEAK,EAAAA,mBAAmBA,GAAG;MACpB,IAAI,IAAI,CAACR,aAAa,CAACkB,YAAY,CAAC,eAAe,CAAC,KAAK,OAAO,EAAE;QAChE,IAAI,CAACN,QAAQ,EAAE;EACjB,KAAC,MAAM;QACL,IAAI,CAACI,QAAQ,EAAE;EACjB;EACF;;EAEA;EACF;EACA;IACEL,eAAeA,CAACQ,KAAK,EAAE;EACrB,IAAA,IACEA,KAAK,CAACC,MAAM,YAAYC,IAAI,IAC5B,CAAC,IAAI,CAACzB,sBAAsB,CAAC0B,QAAQ,CAACH,KAAK,CAACC,MAAM,CAAC,IACnD,CAAC,IAAI,CAAC7B,gBAAgB,CAAC+B,QAAQ,CAACH,KAAK,CAACC,MAAM,CAAC,EAC7C;QACA,IAAI,CAACJ,QAAQ,EAAE;EACjB;EACF;;EAEA;EACF;EACA;EAkCA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA;EACA;EArIahC,YAAY,CAoFhBuC,UAAU,GAAG,mBAAmB;EAEvC;EACF;EACA;EACA;EACA;EA1FavC,YAAY,CA2FhBwC,QAAQ,GAAGC,MAAM,CAACC,MAAM,CAAC;EAC9BlC,EAAAA,eAAe,EAAE;EACfG,IAAAA,QAAQ,EAAE;KACX;EACDU,EAAAA,YAAY,EAAE;EACZC,IAAAA,IAAI,EAAE;KACP;EACDT,EAAAA,qBAAqB,EAAE;EACrBF,IAAAA,QAAQ,EAAE;EACZ;EACF,CAAC,CAAC;EAEF;EACF;EACA;EACA;EACA;EA3GaX,YAAY,CA4GhB2C,MAAM,GAAGF,MAAM,CAACC,MAAM,qBACL;EACpBE,EAAAA,UAAU,EAAE;EACVpC,IAAAA,eAAe,EAAE;EAAEqC,MAAAA,IAAI,EAAE;OAAU;EACnCxB,IAAAA,YAAY,EAAE;EAAEwB,MAAAA,IAAI,EAAE;OAAU;EAChChC,IAAAA,qBAAqB,EAAE;EAAEgC,MAAAA,IAAI,EAAE;EAAS;EAC1C;EACF,CACF,CAAC;;;;;;;;"}