@ministryofjustice/frontend 5.0.0 → 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 (112) hide show
  1. package/moj/all.bundle.js +1549 -1062
  2. package/moj/all.bundle.js.map +1 -1
  3. package/moj/all.bundle.mjs +1845 -1054
  4. package/moj/all.bundle.mjs.map +1 -1
  5. package/moj/all.mjs +7 -90
  6. package/moj/all.mjs.map +1 -1
  7. package/moj/all.scss +1 -0
  8. package/moj/all.scss.map +1 -1
  9. package/moj/common/index.mjs +57 -0
  10. package/moj/common/index.mjs.map +1 -0
  11. package/moj/common/moj-frontend-version.mjs +14 -0
  12. package/moj/common/moj-frontend-version.mjs.map +1 -0
  13. package/moj/components/add-another/add-another.bundle.js +105 -76
  14. package/moj/components/add-another/add-another.bundle.js.map +1 -1
  15. package/moj/components/add-another/add-another.bundle.mjs +222 -71
  16. package/moj/components/add-another/add-another.bundle.mjs.map +1 -1
  17. package/moj/components/add-another/add-another.mjs +103 -72
  18. package/moj/components/add-another/add-another.mjs.map +1 -1
  19. package/moj/components/alert/alert.bundle.js +115 -191
  20. package/moj/components/alert/alert.bundle.js.map +1 -1
  21. package/moj/components/alert/alert.bundle.mjs +354 -186
  22. package/moj/components/alert/alert.bundle.mjs.map +1 -1
  23. package/moj/components/alert/alert.mjs +55 -140
  24. package/moj/components/alert/alert.mjs.map +1 -1
  25. package/moj/components/button-menu/README.md +3 -1
  26. package/moj/components/button-menu/button-menu.bundle.js +91 -120
  27. package/moj/components/button-menu/button-menu.bundle.js.map +1 -1
  28. package/moj/components/button-menu/button-menu.bundle.mjs +329 -114
  29. package/moj/components/button-menu/button-menu.bundle.mjs.map +1 -1
  30. package/moj/components/button-menu/button-menu.mjs +89 -116
  31. package/moj/components/button-menu/button-menu.mjs.map +1 -1
  32. package/moj/components/date-picker/date-picker.bundle.js +174 -154
  33. package/moj/components/date-picker/date-picker.bundle.js.map +1 -1
  34. package/moj/components/date-picker/date-picker.bundle.mjs +411 -147
  35. package/moj/components/date-picker/date-picker.bundle.mjs.map +1 -1
  36. package/moj/components/date-picker/date-picker.mjs +172 -150
  37. package/moj/components/date-picker/date-picker.mjs.map +1 -1
  38. package/moj/components/filter/template.njk +1 -1
  39. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js +133 -44
  40. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js.map +1 -1
  41. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs +374 -41
  42. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs.map +1 -1
  43. package/moj/components/filter-toggle-button/filter-toggle-button.mjs +131 -40
  44. package/moj/components/filter-toggle-button/filter-toggle-button.mjs.map +1 -1
  45. package/moj/components/form-validator/form-validator.bundle.js +159 -69
  46. package/moj/components/form-validator/form-validator.bundle.js.map +1 -1
  47. package/moj/components/form-validator/form-validator.bundle.mjs +399 -65
  48. package/moj/components/form-validator/form-validator.bundle.mjs.map +1 -1
  49. package/moj/components/form-validator/form-validator.mjs +134 -54
  50. package/moj/components/form-validator/form-validator.mjs.map +1 -1
  51. package/moj/components/multi-file-upload/multi-file-upload.bundle.js +291 -117
  52. package/moj/components/multi-file-upload/multi-file-upload.bundle.js.map +1 -1
  53. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs +527 -109
  54. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs.map +1 -1
  55. package/moj/components/multi-file-upload/multi-file-upload.mjs +288 -101
  56. package/moj/components/multi-file-upload/multi-file-upload.mjs.map +1 -1
  57. package/moj/components/multi-file-upload/template.njk +1 -1
  58. package/moj/components/multi-select/multi-select.bundle.js +106 -41
  59. package/moj/components/multi-select/multi-select.bundle.js.map +1 -1
  60. package/moj/components/multi-select/multi-select.bundle.mjs +346 -37
  61. package/moj/components/multi-select/multi-select.bundle.mjs.map +1 -1
  62. package/moj/components/multi-select/multi-select.mjs +104 -37
  63. package/moj/components/multi-select/multi-select.mjs.map +1 -1
  64. package/moj/components/password-reveal/_password-reveal.scss +3 -1
  65. package/moj/components/password-reveal/_password-reveal.scss.map +1 -1
  66. package/moj/components/password-reveal/password-reveal.bundle.js +32 -29
  67. package/moj/components/password-reveal/password-reveal.bundle.js.map +1 -1
  68. package/moj/components/password-reveal/password-reveal.bundle.mjs +149 -24
  69. package/moj/components/password-reveal/password-reveal.bundle.mjs.map +1 -1
  70. package/moj/components/password-reveal/password-reveal.mjs +30 -25
  71. package/moj/components/password-reveal/password-reveal.mjs.map +1 -1
  72. package/moj/components/rich-text-editor/README.md +4 -3
  73. package/moj/components/rich-text-editor/rich-text-editor.bundle.js +127 -62
  74. package/moj/components/rich-text-editor/rich-text-editor.bundle.js.map +1 -1
  75. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs +367 -58
  76. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs.map +1 -1
  77. package/moj/components/rich-text-editor/rich-text-editor.mjs +125 -58
  78. package/moj/components/rich-text-editor/rich-text-editor.mjs.map +1 -1
  79. package/moj/components/search-toggle/search-toggle.bundle.js +94 -26
  80. package/moj/components/search-toggle/search-toggle.bundle.js.map +1 -1
  81. package/moj/components/search-toggle/search-toggle.bundle.mjs +334 -22
  82. package/moj/components/search-toggle/search-toggle.bundle.mjs.map +1 -1
  83. package/moj/components/search-toggle/search-toggle.mjs +92 -22
  84. package/moj/components/search-toggle/search-toggle.mjs.map +1 -1
  85. package/moj/components/sortable-table/sortable-table.bundle.js +151 -83
  86. package/moj/components/sortable-table/sortable-table.bundle.js.map +1 -1
  87. package/moj/components/sortable-table/sortable-table.bundle.mjs +390 -78
  88. package/moj/components/sortable-table/sortable-table.bundle.mjs.map +1 -1
  89. package/moj/components/sortable-table/sortable-table.mjs +149 -79
  90. package/moj/components/sortable-table/sortable-table.mjs.map +1 -1
  91. package/moj/core/_all.scss +3 -0
  92. package/moj/core/_all.scss.map +1 -0
  93. package/moj/core/_moj-frontend-properties.scss +7 -0
  94. package/moj/core/_moj-frontend-properties.scss.map +1 -0
  95. package/moj/filters/prototype-kit-13-filters.js +4 -3
  96. package/moj/helpers.bundle.js +22 -77
  97. package/moj/helpers.bundle.js.map +1 -1
  98. package/moj/helpers.bundle.mjs +23 -74
  99. package/moj/helpers.bundle.mjs.map +1 -1
  100. package/moj/helpers.mjs +23 -74
  101. package/moj/helpers.mjs.map +1 -1
  102. package/moj/moj-frontend.min.css +1 -1
  103. package/moj/moj-frontend.min.css.map +1 -1
  104. package/moj/moj-frontend.min.js +1 -1
  105. package/moj/moj-frontend.min.js.map +1 -1
  106. package/package.json +1 -1
  107. package/moj/version.bundle.js +0 -12
  108. package/moj/version.bundle.js.map +0 -1
  109. package/moj/version.bundle.mjs +0 -4
  110. package/moj/version.bundle.mjs.map +0 -1
  111. package/moj/version.mjs +0 -4
  112. package/moj/version.mjs.map +0 -1
@@ -1,41 +1,166 @@
1
- class PasswordReveal {
1
+ function isInitialised($root, moduleName) {
2
+ return $root instanceof HTMLElement && $root.hasAttribute(`data-${moduleName}-init`);
3
+ }
4
+
5
+ /**
6
+ * Checks if GOV.UK Frontend is supported on this page
7
+ *
8
+ * Some browsers will load and run our JavaScript but GOV.UK Frontend
9
+ * won't be supported.
10
+ *
11
+ * @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support
12
+ * @returns {boolean} Whether GOV.UK Frontend is supported on this page
13
+ */
14
+ function isSupported($scope = document.body) {
15
+ if (!$scope) {
16
+ return false;
17
+ }
18
+ return $scope.classList.contains('govuk-frontend-supported');
19
+ }
20
+ function formatErrorMessage(Component, message) {
21
+ return `${Component.moduleName}: ${message}`;
22
+ }
23
+
24
+ class GOVUKFrontendError extends Error {
25
+ constructor(...args) {
26
+ super(...args);
27
+ this.name = 'GOVUKFrontendError';
28
+ }
29
+ }
30
+ class SupportError extends GOVUKFrontendError {
2
31
  /**
3
- * @param {Element | null} element - HTML element to use for password reveal
32
+ * Checks if GOV.UK Frontend is supported on this page
33
+ *
34
+ * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
4
35
  */
5
- constructor(element) {
6
- if (!element || !(element instanceof HTMLInputElement)) {
7
- return this;
36
+ constructor($scope = document.body) {
37
+ const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
38
+ super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
39
+ this.name = 'SupportError';
40
+ }
41
+ }
42
+ class ElementError extends GOVUKFrontendError {
43
+ constructor(messageOrOptions) {
44
+ let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
45
+ if (typeof messageOrOptions === 'object') {
46
+ const {
47
+ component,
48
+ identifier,
49
+ element,
50
+ expectedType
51
+ } = messageOrOptions;
52
+ message = identifier;
53
+ message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';
54
+ message = formatErrorMessage(component, message);
55
+ }
56
+ super(message);
57
+ this.name = 'ElementError';
58
+ }
59
+ }
60
+ class InitError extends GOVUKFrontendError {
61
+ constructor(componentOrMessage) {
62
+ const message = typeof componentOrMessage === 'string' ? componentOrMessage : formatErrorMessage(componentOrMessage, `Root element (\`$root\`) already initialised`);
63
+ super(message);
64
+ this.name = 'InitError';
65
+ }
66
+ }
67
+
68
+ class Component {
69
+ /**
70
+ * Returns the root element of the component
71
+ *
72
+ * @protected
73
+ * @returns {RootElementType} - the root element of component
74
+ */
75
+ get $root() {
76
+ return this._$root;
77
+ }
78
+ constructor($root) {
79
+ this._$root = void 0;
80
+ const childConstructor = this.constructor;
81
+ if (typeof childConstructor.moduleName !== 'string') {
82
+ throw new InitError(`\`moduleName\` not defined in component`);
8
83
  }
9
- this.el = element;
10
- this.container = element.parentElement;
11
- if (this.container.hasAttribute('data-moj-password-reveal-init')) {
84
+ if (!($root instanceof childConstructor.elementType)) {
85
+ throw new ElementError({
86
+ element: $root,
87
+ component: childConstructor,
88
+ identifier: 'Root element (`$root`)',
89
+ expectedType: childConstructor.elementType.name
90
+ });
91
+ } else {
92
+ this._$root = $root;
93
+ }
94
+ childConstructor.checkSupport();
95
+ this.checkInitialised();
96
+ const moduleName = childConstructor.moduleName;
97
+ this.$root.setAttribute(`data-${moduleName}-init`, '');
98
+ }
99
+ checkInitialised() {
100
+ const constructor = this.constructor;
101
+ const moduleName = constructor.moduleName;
102
+ if (moduleName && isInitialised(this.$root, moduleName)) {
103
+ throw new InitError(constructor);
104
+ }
105
+ }
106
+ static checkSupport() {
107
+ if (!isSupported()) {
108
+ throw new SupportError();
109
+ }
110
+ }
111
+ }
112
+
113
+ /**
114
+ * @typedef ChildClass
115
+ * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component
116
+ */
117
+
118
+ /**
119
+ * @typedef {typeof Component & ChildClass} ChildClassConstructor
120
+ */
121
+ Component.elementType = HTMLElement;
122
+
123
+ class PasswordReveal extends Component {
124
+ /**
125
+ * @param {Element | null} $root - HTML element to use for password reveal
126
+ */
127
+ constructor($root) {
128
+ super($root);
129
+ const $input = this.$root.querySelector('.govuk-input');
130
+ if (!$input || !($input instanceof HTMLInputElement)) {
12
131
  return this;
13
132
  }
14
- this.container.setAttribute('data-moj-password-reveal-init', '');
15
- this.el.setAttribute('spellcheck', 'false');
133
+ this.$input = $input;
134
+ this.$input.setAttribute('spellcheck', 'false');
16
135
  this.createButton();
17
136
  }
18
137
  createButton() {
19
- this.group = document.createElement('div');
20
- this.button = document.createElement('button');
21
- this.button.setAttribute('type', 'button');
22
- this.group.className = 'moj-password-reveal';
23
- this.button.className = 'govuk-button govuk-button--secondary moj-password-reveal__button';
24
- this.button.innerHTML = 'Show <span class="govuk-visually-hidden">password</span>';
25
- this.button.addEventListener('click', this.onButtonClick.bind(this));
26
- this.group.append(this.el, this.button);
27
- this.container.append(this.group);
138
+ this.$group = document.createElement('div');
139
+ this.$button = document.createElement('button');
140
+ this.$button.setAttribute('type', 'button');
141
+ this.$root.classList.add('moj-password-reveal');
142
+ this.$group.classList.add('moj-password-reveal__wrapper');
143
+ this.$button.classList.add('govuk-button', 'govuk-button--secondary', 'moj-password-reveal__button');
144
+ this.$button.innerHTML = 'Show <span class="govuk-visually-hidden">password</span>';
145
+ this.$button.addEventListener('click', this.onButtonClick.bind(this));
146
+ this.$group.append(this.$input, this.$button);
147
+ this.$root.append(this.$group);
28
148
  }
29
149
  onButtonClick() {
30
- if (this.el.type === 'password') {
31
- this.el.type = 'text';
32
- this.button.innerHTML = 'Hide <span class="govuk-visually-hidden">password</span>';
150
+ if (this.$input.type === 'password') {
151
+ this.$input.type = 'text';
152
+ this.$button.innerHTML = 'Hide <span class="govuk-visually-hidden">password</span>';
33
153
  } else {
34
- this.el.type = 'password';
35
- this.button.innerHTML = 'Show <span class="govuk-visually-hidden">password</span>';
154
+ this.$input.type = 'password';
155
+ this.$button.innerHTML = 'Show <span class="govuk-visually-hidden">password</span>';
36
156
  }
37
157
  }
158
+
159
+ /**
160
+ * Name for the component used when initialising using data-module attributes.
161
+ */
38
162
  }
163
+ PasswordReveal.moduleName = 'moj-password-reveal';
39
164
 
40
165
  export { PasswordReveal };
41
166
  //# sourceMappingURL=password-reveal.bundle.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"password-reveal.bundle.mjs","sources":["../../../../src/moj/components/password-reveal/password-reveal.mjs"],"sourcesContent":["export class PasswordReveal {\n /**\n * @param {Element | null} element - HTML element to use for password reveal\n */\n constructor(element) {\n if (!element || !(element instanceof HTMLInputElement)) {\n return this\n }\n\n this.el = element\n this.container = element.parentElement\n\n if (this.container.hasAttribute('data-moj-password-reveal-init')) {\n return this\n }\n\n this.container.setAttribute('data-moj-password-reveal-init', '')\n\n this.el.setAttribute('spellcheck', 'false')\n this.createButton()\n }\n\n createButton() {\n this.group = document.createElement('div')\n this.button = document.createElement('button')\n\n this.button.setAttribute('type', 'button')\n\n this.group.className = 'moj-password-reveal'\n\n this.button.className =\n 'govuk-button govuk-button--secondary moj-password-reveal__button'\n\n this.button.innerHTML =\n 'Show <span class=\"govuk-visually-hidden\">password</span>'\n\n this.button.addEventListener('click', this.onButtonClick.bind(this))\n\n this.group.append(this.el, this.button)\n this.container.append(this.group)\n }\n\n onButtonClick() {\n if (this.el.type === 'password') {\n this.el.type = 'text'\n this.button.innerHTML =\n 'Hide <span class=\"govuk-visually-hidden\">password</span>'\n } else {\n this.el.type = 'password'\n this.button.innerHTML =\n 'Show <span class=\"govuk-visually-hidden\">password</span>'\n }\n }\n}\n"],"names":["PasswordReveal","constructor","element","HTMLInputElement","el","container","parentElement","hasAttribute","setAttribute","createButton","group","document","createElement","button","className","innerHTML","addEventListener","onButtonClick","bind","append","type"],"mappings":"AAAO,MAAMA,cAAc,CAAC;AAC1B;AACF;AACA;EACEC,WAAWA,CAACC,OAAO,EAAE;IACnB,IAAI,CAACA,OAAO,IAAI,EAAEA,OAAO,YAAYC,gBAAgB,CAAC,EAAE;AACtD,MAAA,OAAO,IAAI;AACb;IAEA,IAAI,CAACC,EAAE,GAAGF,OAAO;AACjB,IAAA,IAAI,CAACG,SAAS,GAAGH,OAAO,CAACI,aAAa;IAEtC,IAAI,IAAI,CAACD,SAAS,CAACE,YAAY,CAAC,+BAA+B,CAAC,EAAE;AAChE,MAAA,OAAO,IAAI;AACb;IAEA,IAAI,CAACF,SAAS,CAACG,YAAY,CAAC,+BAA+B,EAAE,EAAE,CAAC;IAEhE,IAAI,CAACJ,EAAE,CAACI,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC;IAC3C,IAAI,CAACC,YAAY,EAAE;AACrB;AAEAA,EAAAA,YAAYA,GAAG;IACb,IAAI,CAACC,KAAK,GAAGC,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;IAC1C,IAAI,CAACC,MAAM,GAAGF,QAAQ,CAACC,aAAa,CAAC,QAAQ,CAAC;IAE9C,IAAI,CAACC,MAAM,CAACL,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;AAE1C,IAAA,IAAI,CAACE,KAAK,CAACI,SAAS,GAAG,qBAAqB;AAE5C,IAAA,IAAI,CAACD,MAAM,CAACC,SAAS,GACnB,kEAAkE;AAEpE,IAAA,IAAI,CAACD,MAAM,CAACE,SAAS,GACnB,0DAA0D;AAE5D,IAAA,IAAI,CAACF,MAAM,CAACG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACC,aAAa,CAACC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEpE,IAAA,IAAI,CAACR,KAAK,CAACS,MAAM,CAAC,IAAI,CAACf,EAAE,EAAE,IAAI,CAACS,MAAM,CAAC;IACvC,IAAI,CAACR,SAAS,CAACc,MAAM,CAAC,IAAI,CAACT,KAAK,CAAC;AACnC;AAEAO,EAAAA,aAAaA,GAAG;AACd,IAAA,IAAI,IAAI,CAACb,EAAE,CAACgB,IAAI,KAAK,UAAU,EAAE;AAC/B,MAAA,IAAI,CAAChB,EAAE,CAACgB,IAAI,GAAG,MAAM;AACrB,MAAA,IAAI,CAACP,MAAM,CAACE,SAAS,GACnB,0DAA0D;AAC9D,KAAC,MAAM;AACL,MAAA,IAAI,CAACX,EAAE,CAACgB,IAAI,GAAG,UAAU;AACzB,MAAA,IAAI,CAACP,MAAM,CAACE,SAAS,GACnB,0DAA0D;AAC9D;AACF;AACF;;;;"}
1
+ {"version":3,"file":"password-reveal.bundle.mjs","sources":["../../../../node_modules/govuk-frontend/dist/govuk/common/index.mjs","../../../../node_modules/govuk-frontend/dist/govuk/errors/index.mjs","../../../../node_modules/govuk-frontend/dist/govuk/component.mjs","../../../../src/moj/components/password-reveal/password-reveal.mjs"],"sourcesContent":["function getFragmentFromUrl(url) {\n if (!url.includes('#')) {\n return undefined;\n }\n return url.split('#').pop();\n}\nfunction getBreakpoint(name) {\n const property = `--govuk-frontend-breakpoint-${name}`;\n const value = window.getComputedStyle(document.documentElement).getPropertyValue(property);\n return {\n property,\n value: value || undefined\n };\n}\nfunction setFocus($element, options = {}) {\n var _options$onBeforeFocu;\n const isFocusable = $element.getAttribute('tabindex');\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1');\n }\n function onFocus() {\n $element.addEventListener('blur', onBlur, {\n once: true\n });\n }\n function onBlur() {\n var _options$onBlur;\n (_options$onBlur = options.onBlur) == null || _options$onBlur.call($element);\n if (!isFocusable) {\n $element.removeAttribute('tabindex');\n }\n }\n $element.addEventListener('focus', onFocus, {\n once: true\n });\n (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);\n $element.focus();\n}\nfunction isInitialised($root, moduleName) {\n return $root instanceof HTMLElement && $root.hasAttribute(`data-${moduleName}-init`);\n}\n\n/**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * Some browsers will load and run our JavaScript but GOV.UK Frontend\n * won't be supported.\n *\n * @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support\n * @returns {boolean} Whether GOV.UK Frontend is supported on this page\n */\nfunction isSupported($scope = document.body) {\n if (!$scope) {\n return false;\n }\n return $scope.classList.contains('govuk-frontend-supported');\n}\nfunction isArray(option) {\n return Array.isArray(option);\n}\nfunction isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option);\n}\nfunction formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`;\n}\n/**\n * @typedef ComponentWithModuleName\n * @property {string} moduleName - Name of the component\n */\n/**\n * @import { ObjectNested } from './configuration.mjs'\n */\n\nexport { formatErrorMessage, getBreakpoint, getFragmentFromUrl, isInitialised, isObject, isSupported, setFocus };\n//# sourceMappingURL=index.mjs.map\n","import { formatErrorMessage } from '../common/index.mjs';\n\nclass GOVUKFrontendError extends Error {\n constructor(...args) {\n super(...args);\n this.name = 'GOVUKFrontendError';\n }\n}\nclass SupportError extends GOVUKFrontendError {\n /**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support\n */\n constructor($scope = document.body) {\n const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class=\"govuk-frontend-supported\">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';\n super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type=\"module\">`');\n this.name = 'SupportError';\n }\n}\nclass ConfigError extends GOVUKFrontendError {\n constructor(...args) {\n super(...args);\n this.name = 'ConfigError';\n }\n}\nclass ElementError extends GOVUKFrontendError {\n constructor(messageOrOptions) {\n let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';\n if (typeof messageOrOptions === 'object') {\n const {\n component,\n identifier,\n element,\n expectedType\n } = messageOrOptions;\n message = identifier;\n message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';\n message = formatErrorMessage(component, message);\n }\n super(message);\n this.name = 'ElementError';\n }\n}\nclass InitError extends GOVUKFrontendError {\n constructor(componentOrMessage) {\n const message = typeof componentOrMessage === 'string' ? componentOrMessage : formatErrorMessage(componentOrMessage, `Root element (\\`$root\\`) already initialised`);\n super(message);\n this.name = 'InitError';\n }\n}\n/**\n * @import { ComponentWithModuleName } from '../common/index.mjs'\n */\n\nexport { ConfigError, ElementError, GOVUKFrontendError, InitError, SupportError };\n//# sourceMappingURL=index.mjs.map\n","import { isInitialised, isSupported } from './common/index.mjs';\nimport { InitError, ElementError, SupportError } from './errors/index.mjs';\n\nclass Component {\n /**\n * Returns the root element of the component\n *\n * @protected\n * @returns {RootElementType} - the root element of component\n */\n get $root() {\n return this._$root;\n }\n constructor($root) {\n this._$root = void 0;\n const childConstructor = this.constructor;\n if (typeof childConstructor.moduleName !== 'string') {\n throw new InitError(`\\`moduleName\\` not defined in component`);\n }\n if (!($root instanceof childConstructor.elementType)) {\n throw new ElementError({\n element: $root,\n component: childConstructor,\n identifier: 'Root element (`$root`)',\n expectedType: childConstructor.elementType.name\n });\n } else {\n this._$root = $root;\n }\n childConstructor.checkSupport();\n this.checkInitialised();\n const moduleName = childConstructor.moduleName;\n this.$root.setAttribute(`data-${moduleName}-init`, '');\n }\n checkInitialised() {\n const constructor = this.constructor;\n const moduleName = constructor.moduleName;\n if (moduleName && isInitialised(this.$root, moduleName)) {\n throw new InitError(constructor);\n }\n }\n static checkSupport() {\n if (!isSupported()) {\n throw new SupportError();\n }\n }\n}\n\n/**\n * @typedef ChildClass\n * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component\n */\n\n/**\n * @typedef {typeof Component & ChildClass} ChildClassConstructor\n */\nComponent.elementType = HTMLElement;\n\nexport { Component };\n//# sourceMappingURL=component.mjs.map\n","import { Component } from 'govuk-frontend'\n\nexport class PasswordReveal extends Component {\n /**\n * @param {Element | null} $root - HTML element to use for password reveal\n */\n constructor($root) {\n super($root)\n\n const $input = this.$root.querySelector('.govuk-input')\n if (!$input || !($input instanceof HTMLInputElement)) {\n return this\n }\n\n this.$input = $input\n this.$input.setAttribute('spellcheck', 'false')\n\n this.createButton()\n }\n\n createButton() {\n this.$group = document.createElement('div')\n this.$button = document.createElement('button')\n\n this.$button.setAttribute('type', 'button')\n\n this.$root.classList.add('moj-password-reveal')\n this.$group.classList.add('moj-password-reveal__wrapper')\n this.$button.classList.add(\n 'govuk-button',\n 'govuk-button--secondary',\n 'moj-password-reveal__button'\n )\n\n this.$button.innerHTML =\n 'Show <span class=\"govuk-visually-hidden\">password</span>'\n\n this.$button.addEventListener('click', this.onButtonClick.bind(this))\n\n this.$group.append(this.$input, this.$button)\n this.$root.append(this.$group)\n }\n\n onButtonClick() {\n if (this.$input.type === 'password') {\n this.$input.type = 'text'\n this.$button.innerHTML =\n 'Hide <span class=\"govuk-visually-hidden\">password</span>'\n } else {\n this.$input.type = 'password'\n this.$button.innerHTML =\n 'Show <span class=\"govuk-visually-hidden\">password</span>'\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-password-reveal'\n}\n"],"names":["isInitialised","$root","moduleName","HTMLElement","hasAttribute","isSupported","$scope","document","body","classList","contains","formatErrorMessage","Component","message","GOVUKFrontendError","Error","constructor","args","name","SupportError","supportMessage","HTMLScriptElement","prototype","ElementError","messageOrOptions","component","identifier","element","expectedType","InitError","componentOrMessage","_$root","childConstructor","elementType","checkSupport","checkInitialised","setAttribute","PasswordReveal","$input","querySelector","HTMLInputElement","createButton","$group","createElement","$button","add","innerHTML","addEventListener","onButtonClick","bind","append","type"],"mappings":"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","x_google_ignoreList":[0,1,2]}
@@ -1,41 +1,46 @@
1
- class PasswordReveal {
1
+ import { Component } from 'govuk-frontend';
2
+
3
+ class PasswordReveal extends Component {
2
4
  /**
3
- * @param {Element | null} element - HTML element to use for password reveal
5
+ * @param {Element | null} $root - HTML element to use for password reveal
4
6
  */
5
- constructor(element) {
6
- if (!element || !(element instanceof HTMLInputElement)) {
7
- return this;
8
- }
9
- this.el = element;
10
- this.container = element.parentElement;
11
- if (this.container.hasAttribute('data-moj-password-reveal-init')) {
7
+ constructor($root) {
8
+ super($root);
9
+ const $input = this.$root.querySelector('.govuk-input');
10
+ if (!$input || !($input instanceof HTMLInputElement)) {
12
11
  return this;
13
12
  }
14
- this.container.setAttribute('data-moj-password-reveal-init', '');
15
- this.el.setAttribute('spellcheck', 'false');
13
+ this.$input = $input;
14
+ this.$input.setAttribute('spellcheck', 'false');
16
15
  this.createButton();
17
16
  }
18
17
  createButton() {
19
- this.group = document.createElement('div');
20
- this.button = document.createElement('button');
21
- this.button.setAttribute('type', 'button');
22
- this.group.className = 'moj-password-reveal';
23
- this.button.className = 'govuk-button govuk-button--secondary moj-password-reveal__button';
24
- this.button.innerHTML = 'Show <span class="govuk-visually-hidden">password</span>';
25
- this.button.addEventListener('click', this.onButtonClick.bind(this));
26
- this.group.append(this.el, this.button);
27
- this.container.append(this.group);
18
+ this.$group = document.createElement('div');
19
+ this.$button = document.createElement('button');
20
+ this.$button.setAttribute('type', 'button');
21
+ this.$root.classList.add('moj-password-reveal');
22
+ this.$group.classList.add('moj-password-reveal__wrapper');
23
+ this.$button.classList.add('govuk-button', 'govuk-button--secondary', 'moj-password-reveal__button');
24
+ this.$button.innerHTML = 'Show <span class="govuk-visually-hidden">password</span>';
25
+ this.$button.addEventListener('click', this.onButtonClick.bind(this));
26
+ this.$group.append(this.$input, this.$button);
27
+ this.$root.append(this.$group);
28
28
  }
29
29
  onButtonClick() {
30
- if (this.el.type === 'password') {
31
- this.el.type = 'text';
32
- this.button.innerHTML = 'Hide <span class="govuk-visually-hidden">password</span>';
30
+ if (this.$input.type === 'password') {
31
+ this.$input.type = 'text';
32
+ this.$button.innerHTML = 'Hide <span class="govuk-visually-hidden">password</span>';
33
33
  } else {
34
- this.el.type = 'password';
35
- this.button.innerHTML = 'Show <span class="govuk-visually-hidden">password</span>';
34
+ this.$input.type = 'password';
35
+ this.$button.innerHTML = 'Show <span class="govuk-visually-hidden">password</span>';
36
36
  }
37
37
  }
38
+
39
+ /**
40
+ * Name for the component used when initialising using data-module attributes.
41
+ */
38
42
  }
43
+ PasswordReveal.moduleName = 'moj-password-reveal';
39
44
 
40
45
  export { PasswordReveal };
41
46
  //# sourceMappingURL=password-reveal.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"password-reveal.mjs","sources":["../../../../src/moj/components/password-reveal/password-reveal.mjs"],"sourcesContent":["export class PasswordReveal {\n /**\n * @param {Element | null} element - HTML element to use for password reveal\n */\n constructor(element) {\n if (!element || !(element instanceof HTMLInputElement)) {\n return this\n }\n\n this.el = element\n this.container = element.parentElement\n\n if (this.container.hasAttribute('data-moj-password-reveal-init')) {\n return this\n }\n\n this.container.setAttribute('data-moj-password-reveal-init', '')\n\n this.el.setAttribute('spellcheck', 'false')\n this.createButton()\n }\n\n createButton() {\n this.group = document.createElement('div')\n this.button = document.createElement('button')\n\n this.button.setAttribute('type', 'button')\n\n this.group.className = 'moj-password-reveal'\n\n this.button.className =\n 'govuk-button govuk-button--secondary moj-password-reveal__button'\n\n this.button.innerHTML =\n 'Show <span class=\"govuk-visually-hidden\">password</span>'\n\n this.button.addEventListener('click', this.onButtonClick.bind(this))\n\n this.group.append(this.el, this.button)\n this.container.append(this.group)\n }\n\n onButtonClick() {\n if (this.el.type === 'password') {\n this.el.type = 'text'\n this.button.innerHTML =\n 'Hide <span class=\"govuk-visually-hidden\">password</span>'\n } else {\n this.el.type = 'password'\n this.button.innerHTML =\n 'Show <span class=\"govuk-visually-hidden\">password</span>'\n }\n }\n}\n"],"names":["PasswordReveal","constructor","element","HTMLInputElement","el","container","parentElement","hasAttribute","setAttribute","createButton","group","document","createElement","button","className","innerHTML","addEventListener","onButtonClick","bind","append","type"],"mappings":"AAAO,MAAMA,cAAc,CAAC;AAC1B;AACF;AACA;EACEC,WAAWA,CAACC,OAAO,EAAE;IACnB,IAAI,CAACA,OAAO,IAAI,EAAEA,OAAO,YAAYC,gBAAgB,CAAC,EAAE;AACtD,MAAA,OAAO,IAAI;AACb;IAEA,IAAI,CAACC,EAAE,GAAGF,OAAO;AACjB,IAAA,IAAI,CAACG,SAAS,GAAGH,OAAO,CAACI,aAAa;IAEtC,IAAI,IAAI,CAACD,SAAS,CAACE,YAAY,CAAC,+BAA+B,CAAC,EAAE;AAChE,MAAA,OAAO,IAAI;AACb;IAEA,IAAI,CAACF,SAAS,CAACG,YAAY,CAAC,+BAA+B,EAAE,EAAE,CAAC;IAEhE,IAAI,CAACJ,EAAE,CAACI,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC;IAC3C,IAAI,CAACC,YAAY,EAAE;AACrB;AAEAA,EAAAA,YAAYA,GAAG;IACb,IAAI,CAACC,KAAK,GAAGC,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;IAC1C,IAAI,CAACC,MAAM,GAAGF,QAAQ,CAACC,aAAa,CAAC,QAAQ,CAAC;IAE9C,IAAI,CAACC,MAAM,CAACL,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;AAE1C,IAAA,IAAI,CAACE,KAAK,CAACI,SAAS,GAAG,qBAAqB;AAE5C,IAAA,IAAI,CAACD,MAAM,CAACC,SAAS,GACnB,kEAAkE;AAEpE,IAAA,IAAI,CAACD,MAAM,CAACE,SAAS,GACnB,0DAA0D;AAE5D,IAAA,IAAI,CAACF,MAAM,CAACG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACC,aAAa,CAACC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEpE,IAAA,IAAI,CAACR,KAAK,CAACS,MAAM,CAAC,IAAI,CAACf,EAAE,EAAE,IAAI,CAACS,MAAM,CAAC;IACvC,IAAI,CAACR,SAAS,CAACc,MAAM,CAAC,IAAI,CAACT,KAAK,CAAC;AACnC;AAEAO,EAAAA,aAAaA,GAAG;AACd,IAAA,IAAI,IAAI,CAACb,EAAE,CAACgB,IAAI,KAAK,UAAU,EAAE;AAC/B,MAAA,IAAI,CAAChB,EAAE,CAACgB,IAAI,GAAG,MAAM;AACrB,MAAA,IAAI,CAACP,MAAM,CAACE,SAAS,GACnB,0DAA0D;AAC9D,KAAC,MAAM;AACL,MAAA,IAAI,CAACX,EAAE,CAACgB,IAAI,GAAG,UAAU;AACzB,MAAA,IAAI,CAACP,MAAM,CAACE,SAAS,GACnB,0DAA0D;AAC9D;AACF;AACF;;;;"}
1
+ {"version":3,"file":"password-reveal.mjs","sources":["../../../../src/moj/components/password-reveal/password-reveal.mjs"],"sourcesContent":["import { Component } from 'govuk-frontend'\n\nexport class PasswordReveal extends Component {\n /**\n * @param {Element | null} $root - HTML element to use for password reveal\n */\n constructor($root) {\n super($root)\n\n const $input = this.$root.querySelector('.govuk-input')\n if (!$input || !($input instanceof HTMLInputElement)) {\n return this\n }\n\n this.$input = $input\n this.$input.setAttribute('spellcheck', 'false')\n\n this.createButton()\n }\n\n createButton() {\n this.$group = document.createElement('div')\n this.$button = document.createElement('button')\n\n this.$button.setAttribute('type', 'button')\n\n this.$root.classList.add('moj-password-reveal')\n this.$group.classList.add('moj-password-reveal__wrapper')\n this.$button.classList.add(\n 'govuk-button',\n 'govuk-button--secondary',\n 'moj-password-reveal__button'\n )\n\n this.$button.innerHTML =\n 'Show <span class=\"govuk-visually-hidden\">password</span>'\n\n this.$button.addEventListener('click', this.onButtonClick.bind(this))\n\n this.$group.append(this.$input, this.$button)\n this.$root.append(this.$group)\n }\n\n onButtonClick() {\n if (this.$input.type === 'password') {\n this.$input.type = 'text'\n this.$button.innerHTML =\n 'Hide <span class=\"govuk-visually-hidden\">password</span>'\n } else {\n this.$input.type = 'password'\n this.$button.innerHTML =\n 'Show <span class=\"govuk-visually-hidden\">password</span>'\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-password-reveal'\n}\n"],"names":["PasswordReveal","Component","constructor","$root","$input","querySelector","HTMLInputElement","setAttribute","createButton","$group","document","createElement","$button","classList","add","innerHTML","addEventListener","onButtonClick","bind","append","type","moduleName"],"mappings":";;AAEO,MAAMA,cAAc,SAASC,SAAS,CAAC;AAC5C;AACF;AACA;EACEC,WAAWA,CAACC,KAAK,EAAE;IACjB,KAAK,CAACA,KAAK,CAAC;IAEZ,MAAMC,MAAM,GAAG,IAAI,CAACD,KAAK,CAACE,aAAa,CAAC,cAAc,CAAC;IACvD,IAAI,CAACD,MAAM,IAAI,EAAEA,MAAM,YAAYE,gBAAgB,CAAC,EAAE;AACpD,MAAA,OAAO,IAAI;AACb;IAEA,IAAI,CAACF,MAAM,GAAGA,MAAM;IACpB,IAAI,CAACA,MAAM,CAACG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC;IAE/C,IAAI,CAACC,YAAY,EAAE;AACrB;AAEAA,EAAAA,YAAYA,GAAG;IACb,IAAI,CAACC,MAAM,GAAGC,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;IAC3C,IAAI,CAACC,OAAO,GAAGF,QAAQ,CAACC,aAAa,CAAC,QAAQ,CAAC;IAE/C,IAAI,CAACC,OAAO,CAACL,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;IAE3C,IAAI,CAACJ,KAAK,CAACU,SAAS,CAACC,GAAG,CAAC,qBAAqB,CAAC;IAC/C,IAAI,CAACL,MAAM,CAACI,SAAS,CAACC,GAAG,CAAC,8BAA8B,CAAC;AACzD,IAAA,IAAI,CAACF,OAAO,CAACC,SAAS,CAACC,GAAG,CACxB,cAAc,EACd,yBAAyB,EACzB,6BACF,CAAC;AAED,IAAA,IAAI,CAACF,OAAO,CAACG,SAAS,GACpB,0DAA0D;AAE5D,IAAA,IAAI,CAACH,OAAO,CAACI,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACC,aAAa,CAACC,IAAI,CAAC,IAAI,CAAC,CAAC;AAErE,IAAA,IAAI,CAACT,MAAM,CAACU,MAAM,CAAC,IAAI,CAACf,MAAM,EAAE,IAAI,CAACQ,OAAO,CAAC;IAC7C,IAAI,CAACT,KAAK,CAACgB,MAAM,CAAC,IAAI,CAACV,MAAM,CAAC;AAChC;AAEAQ,EAAAA,aAAaA,GAAG;AACd,IAAA,IAAI,IAAI,CAACb,MAAM,CAACgB,IAAI,KAAK,UAAU,EAAE;AACnC,MAAA,IAAI,CAAChB,MAAM,CAACgB,IAAI,GAAG,MAAM;AACzB,MAAA,IAAI,CAACR,OAAO,CAACG,SAAS,GACpB,0DAA0D;AAC9D,KAAC,MAAM;AACL,MAAA,IAAI,CAACX,MAAM,CAACgB,IAAI,GAAG,UAAU;AAC7B,MAAA,IAAI,CAACR,OAAO,CAACG,SAAS,GACpB,0DAA0D;AAC9D;AACF;;AAEA;AACF;AACA;AAEA;AAzDaf,cAAc,CAwDlBqB,UAAU,GAAG,qBAAqB;;;;"}
@@ -7,10 +7,11 @@
7
7
  ```mjs
8
8
  import { RichTextEditor } from '@ministryofjustice/frontend'
9
9
 
10
- const $richTextEditor = document.querySelector('.app-rich-text-editor')
10
+ const $richTextEditor = document.querySelector(
11
+ '[data-module="moj-rich-text-editor"]'
12
+ )
11
13
 
12
- new RichTextEditor({
13
- textarea: $richTextEditor,
14
+ new RichTextEditor($richTextEditor, {
14
15
  toolbar: {
15
16
  bold: true,
16
17
  italic: true,
@@ -1,34 +1,27 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MOJFrontend = global.MOJFrontend || {}));
5
- })(this, (function (exports) { 'use strict';
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
6
 
7
- class RichTextEditor {
7
+ /**
8
+ * @augments {ConfigurableComponent<RichTextEditorConfig>}
9
+ */
10
+ class RichTextEditor extends govukFrontend.ConfigurableComponent {
8
11
  /**
9
- * @param {RichTextEditorConfig} options
12
+ * @param {Element | null} $root - HTML element to use for rich text editor
13
+ * @param {RichTextEditorConfig} config
10
14
  */
11
- constructor(options = {}) {
12
- const {
13
- textarea
14
- } = options;
15
- if (!textarea || !textarea.parentElement || !(textarea instanceof HTMLTextAreaElement) || !('contentEditable' in document.documentElement)) {
15
+ constructor($root, config = {}) {
16
+ super($root, config);
17
+ if (!RichTextEditor.isSupported()) {
16
18
  return this;
17
19
  }
18
- options.toolbar = options.toolbar || {
19
- bold: false,
20
- italic: false,
21
- underline: false,
22
- bullets: true,
23
- numbers: true
24
- };
25
- this.textarea = textarea;
26
- this.container = this.textarea.parentElement;
27
- this.options = options;
28
- if (this.container.hasAttribute('data-rich-text-editor-init')) {
20
+ const $textarea = this.$root.querySelector('.govuk-textarea');
21
+ if (!$textarea || !($textarea instanceof HTMLTextAreaElement)) {
29
22
  return this;
30
23
  }
31
- this.container.setAttribute('data-rich-text-editor-init', '');
24
+ this.$textarea = $textarea;
32
25
  this.createToolbar();
33
26
  this.hideDefault();
34
27
  this.configureToolbar();
@@ -38,34 +31,42 @@
38
31
  up: 38,
39
32
  down: 40
40
33
  };
41
- this.content.addEventListener('input', this.onEditorInput.bind(this));
42
- this.container.querySelector('label').addEventListener('click', this.onLabelClick.bind(this));
43
- this.toolbar.addEventListener('keydown', this.onToolbarKeydown.bind(this));
34
+ this.$content.addEventListener('input', this.onEditorInput.bind(this));
35
+ this.$root.querySelector('label').addEventListener('click', this.onLabelClick.bind(this));
36
+ this.$toolbar.addEventListener('keydown', this.onToolbarKeydown.bind(this));
44
37
  }
38
+
39
+ /**
40
+ * @param {KeyboardEvent} event - Click event
41
+ */
45
42
  onToolbarKeydown(event) {
46
- let focusableButton;
43
+ let $focusableButton;
47
44
  switch (event.keyCode) {
48
45
  case this.keys.right:
49
46
  case this.keys.down:
50
47
  {
51
- focusableButton = this.buttons.find(button => button.getAttribute('tabindex') === '0');
52
- const nextButton = focusableButton.nextElementSibling;
53
- if (nextButton instanceof HTMLButtonElement) {
54
- nextButton.focus();
55
- focusableButton.setAttribute('tabindex', '-1');
56
- nextButton.setAttribute('tabindex', '0');
48
+ $focusableButton = this.$buttons.find(button => button.getAttribute('tabindex') === '0');
49
+ if ($focusableButton) {
50
+ const $nextButton = $focusableButton.nextElementSibling;
51
+ if ($nextButton && $nextButton instanceof HTMLButtonElement) {
52
+ $nextButton.focus();
53
+ $focusableButton.setAttribute('tabindex', '-1');
54
+ $nextButton.setAttribute('tabindex', '0');
55
+ }
57
56
  }
58
57
  break;
59
58
  }
60
59
  case this.keys.left:
61
60
  case this.keys.up:
62
61
  {
63
- focusableButton = this.buttons.find(button => button.getAttribute('tabindex') === '0');
64
- const previousButton = focusableButton.previousElementSibling;
65
- if (previousButton instanceof HTMLButtonElement) {
66
- previousButton.focus();
67
- focusableButton.setAttribute('tabindex', '-1');
68
- previousButton.setAttribute('tabindex', '0');
62
+ $focusableButton = this.$buttons.find(button => button.getAttribute('tabindex') === '0');
63
+ if ($focusableButton) {
64
+ const $previousButton = $focusableButton.previousElementSibling;
65
+ if ($previousButton && $previousButton instanceof HTMLButtonElement) {
66
+ $previousButton.focus();
67
+ $focusableButton.setAttribute('tabindex', '-1');
68
+ $previousButton.setAttribute('tabindex', '0');
69
+ }
69
70
  }
70
71
  break;
71
72
  }
@@ -74,19 +75,19 @@
74
75
  getToolbarHtml() {
75
76
  let html = '';
76
77
  html += '<div class="moj-rich-text-editor__toolbar" role="toolbar">';
77
- if (this.options.toolbar.bold) {
78
+ if (this.config.toolbar.bold) {
78
79
  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>';
79
80
  }
80
- if (this.options.toolbar.italic) {
81
+ if (this.config.toolbar.italic) {
81
82
  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>';
82
83
  }
83
- if (this.options.toolbar.underline) {
84
+ if (this.config.toolbar.underline) {
84
85
  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>';
85
86
  }
86
- if (this.options.toolbar.bullets) {
87
+ if (this.config.toolbar.bullets) {
87
88
  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>';
88
89
  }
89
- if (this.options.toolbar.numbers) {
90
+ if (this.config.toolbar.numbers) {
90
91
  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>';
91
92
  }
92
93
  html += '</div>';
@@ -96,27 +97,31 @@
96
97
  return `${this.getToolbarHtml()}<div class="govuk-textarea moj-rich-text-editor__content" contenteditable="true" spellcheck="false"></div>`;
97
98
  }
98
99
  hideDefault() {
99
- this.textarea.classList.add('govuk-visually-hidden');
100
- this.textarea.setAttribute('aria-hidden', 'true');
101
- this.textarea.setAttribute('tabindex', '-1');
100
+ this.$textarea.classList.add('govuk-visually-hidden');
101
+ this.$textarea.setAttribute('aria-hidden', 'true');
102
+ this.$textarea.setAttribute('tabindex', '-1');
102
103
  }
103
104
  createToolbar() {
104
- this.toolbar = document.createElement('div');
105
- this.toolbar.className = 'moj-rich-text-editor';
106
- this.toolbar.innerHTML = this.getEnhancedHtml();
107
- this.container.append(this.toolbar);
108
- this.content = /** @type {HTMLDivElement} */
109
- this.container.querySelector('.moj-rich-text-editor__content');
110
- this.content.innerHTML = this.$textarea.value;
105
+ this.$toolbar = document.createElement('div');
106
+ this.$toolbar.className = 'moj-rich-text-editor';
107
+ this.$toolbar.innerHTML = this.getEnhancedHtml();
108
+ this.$root.append(this.$toolbar);
109
+ this.$content = /** @type {HTMLElement} */
110
+ this.$root.querySelector('.moj-rich-text-editor__content');
111
+ this.$content.innerHTML = this.$textarea.value;
111
112
  }
112
113
  configureToolbar() {
113
- this.buttons = Array.from(/** @type {NodeListOf<HTMLButtonElement>} */
114
- this.container.querySelectorAll('.moj-rich-text-editor__toolbar-button'));
115
- this.buttons.forEach((button, index) => {
116
- button.setAttribute('tabindex', !index ? '0' : '-1');
117
- button.addEventListener('click', this.onButtonClick.bind(this));
114
+ this.$buttons = Array.from(/** @type {NodeListOf<HTMLButtonElement>} */
115
+ this.$root.querySelectorAll('.moj-rich-text-editor__toolbar-button'));
116
+ this.$buttons.forEach(($button, index) => {
117
+ $button.setAttribute('tabindex', !index ? '0' : '-1');
118
+ $button.addEventListener('click', this.onButtonClick.bind(this));
118
119
  });
119
120
  }
121
+
122
+ /**
123
+ * @param {MouseEvent} event - Click event
124
+ */
120
125
  onButtonClick(event) {
121
126
  if (!(event.currentTarget instanceof HTMLElement)) {
122
127
  return;
@@ -124,21 +129,81 @@
124
129
  document.execCommand(event.currentTarget.getAttribute('data-command'), false, undefined);
125
130
  }
126
131
  getContent() {
127
- return this.content.innerHTML;
132
+ return this.$content.innerHTML;
128
133
  }
129
134
  onEditorInput() {
130
135
  this.updateTextarea();
131
136
  }
132
137
  updateTextarea() {
133
138
  document.execCommand('defaultParagraphSeparator', false, 'p');
134
- this.textarea.value = this.getContent();
139
+ this.$textarea.value = this.getContent();
135
140
  }
141
+
142
+ /**
143
+ * @param {MouseEvent} event - Click event
144
+ */
136
145
  onLabelClick(event) {
137
146
  event.preventDefault();
138
- this.content.focus();
147
+ this.$content.focus();
139
148
  }
149
+ static isSupported() {
150
+ return 'contentEditable' in document.documentElement;
151
+ }
152
+
153
+ /**
154
+ * Name for the component used when initialising using data-module attributes.
155
+ */
140
156
  }
141
157
 
158
+ /**
159
+ * Rich text editor config
160
+ *
161
+ * @typedef {object} RichTextEditorConfig
162
+ * @property {RichTextEditorToolbar} [toolbar] - Toolbar options
163
+ */
164
+
165
+ /**
166
+ * Rich text editor toolbar options
167
+ *
168
+ * @typedef {object} RichTextEditorToolbar
169
+ * @property {boolean} [bold] - Show the bold button
170
+ * @property {boolean} [italic] - Show the italic button
171
+ * @property {boolean} [underline] - Show the underline button
172
+ * @property {boolean} [bullets] - Show the bullets button
173
+ * @property {boolean} [numbers] - Show the numbers button
174
+ */
175
+
176
+ /**
177
+ * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
178
+ */
179
+ RichTextEditor.moduleName = 'moj-rich-text-editor';
180
+ /**
181
+ * Rich text editor config
182
+ *
183
+ * @type {RichTextEditorConfig}
184
+ */
185
+ RichTextEditor.defaults = Object.freeze({
186
+ toolbar: {
187
+ bold: false,
188
+ italic: false,
189
+ underline: false,
190
+ bullets: true,
191
+ numbers: true
192
+ }
193
+ });
194
+ /**
195
+ * Rich text editor config schema
196
+ *
197
+ * @satisfies {Schema<RichTextEditorConfig>}
198
+ */
199
+ RichTextEditor.schema = Object.freeze(/** @type {const} */{
200
+ properties: {
201
+ toolbar: {
202
+ type: 'object'
203
+ }
204
+ }
205
+ });
206
+
142
207
  exports.RichTextEditor = RichTextEditor;
143
208
 
144
209
  }));