govuk_publishing_components 44.1.0 → 44.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/lib/govuk_publishing_components/version.rb +1 -1
  3. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +336 -225
  4. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js.map +1 -1
  5. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +334 -226
  6. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs.map +1 -1
  7. data/node_modules/govuk-frontend/dist/govuk/all.mjs +3 -0
  8. data/node_modules/govuk-frontend/dist/govuk/all.mjs.map +1 -1
  9. data/node_modules/govuk-frontend/dist/govuk/assets/images/govuk-crest.svg +1 -0
  10. data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
  11. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs +21 -1
  12. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs.map +1 -1
  13. data/node_modules/govuk-frontend/dist/govuk/components/_index.scss +1 -0
  14. data/node_modules/govuk-frontend/dist/govuk/components/_index.scss.map +1 -1
  15. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +92 -26
  16. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js.map +1 -1
  17. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +92 -26
  18. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs.map +1 -1
  19. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +12 -21
  20. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs.map +1 -1
  21. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +86 -20
  22. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js.map +1 -1
  23. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +86 -20
  24. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs.map +1 -1
  25. data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs +6 -16
  26. data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs.map +1 -1
  27. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +89 -23
  28. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js.map +1 -1
  29. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +89 -23
  30. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs.map +1 -1
  31. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +10 -19
  32. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs.map +1 -1
  33. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +113 -47
  34. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js.map +1 -1
  35. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +113 -47
  36. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs.map +1 -1
  37. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs +7 -16
  38. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs.map +1 -1
  39. data/node_modules/govuk-frontend/dist/govuk/components/details/_index.scss +7 -2
  40. data/node_modules/govuk-frontend/dist/govuk/components/details/_index.scss.map +1 -1
  41. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +86 -20
  42. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js.map +1 -1
  43. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +86 -20
  44. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs.map +1 -1
  45. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs +6 -16
  46. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs.map +1 -1
  47. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +87 -21
  48. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js.map +1 -1
  49. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +87 -21
  50. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs.map +1 -1
  51. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs +7 -16
  52. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs.map +1 -1
  53. data/node_modules/govuk-frontend/dist/govuk/components/footer/_index.scss +8 -10
  54. data/node_modules/govuk-frontend/dist/govuk/components/footer/_index.scss.map +1 -1
  55. data/node_modules/govuk-frontend/dist/govuk/components/header/_index.scss +8 -0
  56. data/node_modules/govuk-frontend/dist/govuk/components/header/_index.scss.map +1 -1
  57. data/node_modules/govuk-frontend/dist/govuk/components/header/fixtures.json +12 -0
  58. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js +87 -21
  59. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js.map +1 -1
  60. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs +87 -21
  61. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs.map +1 -1
  62. data/node_modules/govuk-frontend/dist/govuk/components/header/header.mjs +7 -16
  63. data/node_modules/govuk-frontend/dist/govuk/components/header/header.mjs.map +1 -1
  64. data/node_modules/govuk-frontend/dist/govuk/components/header/template-with-full-width-border.html +24 -0
  65. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +86 -20
  66. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js.map +1 -1
  67. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +86 -20
  68. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs.map +1 -1
  69. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs +6 -16
  70. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs.map +1 -1
  71. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +89 -23
  72. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js.map +1 -1
  73. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +89 -23
  74. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs.map +1 -1
  75. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs +9 -18
  76. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs.map +1 -1
  77. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +113 -47
  78. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js.map +1 -1
  79. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +113 -47
  80. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs.map +1 -1
  81. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.mjs +7 -16
  82. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.mjs.map +1 -1
  83. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/README.md +15 -0
  84. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/_index.scss +168 -0
  85. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/_index.scss.map +1 -0
  86. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/_service-navigation.scss +4 -0
  87. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/_service-navigation.scss.map +1 -0
  88. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/fixtures.json +464 -0
  89. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/macro-options.json +138 -0
  90. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/macro.njk +3 -0
  91. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +249 -0
  92. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js.map +1 -0
  93. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +241 -0
  94. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs.map +1 -0
  95. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.mjs +85 -0
  96. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.mjs.map +1 -0
  97. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-default.html +57 -0
  98. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-html-navigation-items.html +49 -0
  99. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-large-navigation.html +153 -0
  100. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-long-service-name.html +20 -0
  101. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-navigation-with-a-current-item.html +58 -0
  102. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-navigation-with-an-active-item.html +58 -0
  103. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-non-link-navigation-items.html +49 -0
  104. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-service-link.html +20 -0
  105. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-service-name-and-navigation.html +63 -0
  106. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-service-name.html +18 -0
  107. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template.njk +102 -0
  108. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +93 -26
  109. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js.map +1 -1
  110. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +93 -26
  111. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs.map +1 -1
  112. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs +13 -21
  113. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs.map +1 -1
  114. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +93 -27
  115. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js.map +1 -1
  116. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +93 -27
  117. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs.map +1 -1
  118. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs +13 -22
  119. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs.map +1 -1
  120. data/node_modules/govuk-frontend/dist/govuk/components/warning-text/_index.scss +4 -3
  121. data/node_modules/govuk-frontend/dist/govuk/components/warning-text/_index.scss.map +1 -1
  122. data/node_modules/govuk-frontend/dist/govuk/core/_govuk-frontend-properties.scss +1 -1
  123. data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs +16 -3
  124. data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs.map +1 -1
  125. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend-component.mjs +49 -5
  126. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend-component.mjs.map +1 -1
  127. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css +2 -2
  128. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css.map +1 -1
  129. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
  130. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js.map +1 -1
  131. data/node_modules/govuk-frontend/dist/govuk/init.mjs +72 -10
  132. data/node_modules/govuk-frontend/dist/govuk/init.mjs.map +1 -1
  133. data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss +3 -0
  134. data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss.map +1 -1
  135. data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +5 -1
  136. data/node_modules/govuk-frontend/package.json +8 -8
  137. metadata +29 -4
  138. data/node_modules/govuk-frontend/dist/govuk/assets/images/govuk-crest-2x.png +0 -0
  139. data/node_modules/govuk-frontend/dist/govuk/assets/images/govuk-crest.png +0 -0
@@ -1,3 +1,53 @@
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
+ /**
25
+ * Schema for component config
26
+ *
27
+ * @typedef {object} Schema
28
+ * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
29
+ * @property {SchemaCondition[]} [anyOf] - List of schema conditions
30
+ */
31
+
32
+ /**
33
+ * Schema property for component config
34
+ *
35
+ * @typedef {object} SchemaProperty
36
+ * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
37
+ */
38
+
39
+ /**
40
+ * Schema condition for component config
41
+ *
42
+ * @typedef {object} SchemaCondition
43
+ * @property {string[]} required - List of required config fields
44
+ * @property {string} errorMessage - Error message when required config fields not provided
45
+ */
46
+ /**
47
+ * @typedef ComponentWithModuleName
48
+ * @property {string} moduleName - Name of the component
49
+ */
50
+
1
51
  class GOVUKFrontendError extends Error {
2
52
  constructor(...args) {
3
53
  super(...args);
@@ -21,60 +71,85 @@ class ElementError extends GOVUKFrontendError {
21
71
  let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
22
72
  if (typeof messageOrOptions === 'object') {
23
73
  const {
24
- componentName,
74
+ component,
25
75
  identifier,
26
76
  element,
27
77
  expectedType
28
78
  } = messageOrOptions;
29
- message = `${componentName}: ${identifier}`;
79
+ message = identifier;
30
80
  message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';
81
+ message = formatErrorMessage(component, message);
31
82
  }
32
83
  super(message);
33
84
  this.name = 'ElementError';
34
85
  }
35
86
  }
36
-
37
- function isSupported($scope = document.body) {
38
- if (!$scope) {
39
- return false;
87
+ class InitError extends GOVUKFrontendError {
88
+ constructor(componentOrMessage) {
89
+ const message = typeof componentOrMessage === 'string' ? componentOrMessage : formatErrorMessage(componentOrMessage, `Root element (\`$root\`) already initialised`);
90
+ super(message);
91
+ this.name = 'InitError';
40
92
  }
41
- return $scope.classList.contains('govuk-frontend-supported');
42
93
  }
43
-
44
- /**
45
- * Schema for component config
46
- *
47
- * @typedef {object} Schema
48
- * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
49
- * @property {SchemaCondition[]} [anyOf] - List of schema conditions
50
- */
51
-
52
94
  /**
53
- * Schema property for component config
54
- *
55
- * @typedef {object} SchemaProperty
56
- * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
57
- */
58
-
59
- /**
60
- * Schema condition for component config
61
- *
62
- * @typedef {object} SchemaCondition
63
- * @property {string[]} required - List of required config fields
64
- * @property {string} errorMessage - Error message when required config fields not provided
95
+ * @typedef {import('../common/index.mjs').ComponentWithModuleName} ComponentWithModuleName
65
96
  */
66
97
 
67
98
  class GOVUKFrontendComponent {
68
- constructor() {
69
- this.checkSupport();
99
+ /**
100
+ * Returns the root element of the component
101
+ *
102
+ * @protected
103
+ * @returns {RootElementType} - the root element of component
104
+ */
105
+ get $root() {
106
+ return this._$root;
70
107
  }
71
- checkSupport() {
108
+ constructor($root) {
109
+ this._$root = void 0;
110
+ const childConstructor = this.constructor;
111
+ if (typeof childConstructor.moduleName !== 'string') {
112
+ throw new InitError(`\`moduleName\` not defined in component`);
113
+ }
114
+ if (!($root instanceof childConstructor.elementType)) {
115
+ throw new ElementError({
116
+ element: $root,
117
+ component: childConstructor,
118
+ identifier: 'Root element (`$root`)',
119
+ expectedType: childConstructor.elementType.name
120
+ });
121
+ } else {
122
+ this._$root = $root;
123
+ }
124
+ childConstructor.checkSupport();
125
+ this.checkInitialised();
126
+ const moduleName = childConstructor.moduleName;
127
+ this.$root.setAttribute(`data-${moduleName}-init`, '');
128
+ }
129
+ checkInitialised() {
130
+ const constructor = this.constructor;
131
+ const moduleName = constructor.moduleName;
132
+ if (moduleName && isInitialised(this.$root, moduleName)) {
133
+ throw new InitError(constructor);
134
+ }
135
+ }
136
+ static checkSupport() {
72
137
  if (!isSupported()) {
73
138
  throw new SupportError();
74
139
  }
75
140
  }
76
141
  }
77
142
 
143
+ /**
144
+ * @typedef ChildClass
145
+ * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component
146
+ */
147
+
148
+ /**
149
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
150
+ */
151
+ GOVUKFrontendComponent.elementType = HTMLElement;
152
+
78
153
  /**
79
154
  * Checkboxes component
80
155
  *
@@ -93,27 +168,18 @@ class Checkboxes extends GOVUKFrontendComponent {
93
168
  * (for example if the user has navigated back), and set up event handlers to
94
169
  * keep the reveal in sync with the checkbox state.
95
170
  *
96
- * @param {Element | null} $module - HTML element to use for checkboxes
171
+ * @param {Element | null} $root - HTML element to use for checkboxes
97
172
  */
98
- constructor($module) {
99
- super();
100
- this.$module = void 0;
173
+ constructor($root) {
174
+ super($root);
101
175
  this.$inputs = void 0;
102
- if (!($module instanceof HTMLElement)) {
103
- throw new ElementError({
104
- componentName: 'Checkboxes',
105
- element: $module,
106
- identifier: 'Root element (`$module`)'
107
- });
108
- }
109
- const $inputs = $module.querySelectorAll('input[type="checkbox"]');
176
+ const $inputs = this.$root.querySelectorAll('input[type="checkbox"]');
110
177
  if (!$inputs.length) {
111
178
  throw new ElementError({
112
- componentName: 'Checkboxes',
179
+ component: Checkboxes,
113
180
  identifier: 'Form inputs (`<input type="checkbox">`)'
114
181
  });
115
182
  }
116
- this.$module = $module;
117
183
  this.$inputs = $inputs;
118
184
  this.$inputs.forEach($input => {
119
185
  const targetId = $input.getAttribute('data-aria-controls');
@@ -122,7 +188,7 @@ class Checkboxes extends GOVUKFrontendComponent {
122
188
  }
123
189
  if (!document.getElementById(targetId)) {
124
190
  throw new ElementError({
125
- componentName: 'Checkboxes',
191
+ component: Checkboxes,
126
192
  identifier: `Conditional reveal (\`id="${targetId}"\`)`
127
193
  });
128
194
  }
@@ -131,7 +197,7 @@ class Checkboxes extends GOVUKFrontendComponent {
131
197
  });
132
198
  window.addEventListener('pageshow', () => this.syncAllConditionalReveals());
133
199
  this.syncAllConditionalReveals();
134
- this.$module.addEventListener('click', event => this.handleClick(event));
200
+ this.$root.addEventListener('click', event => this.handleClick(event));
135
201
  }
136
202
  syncAllConditionalReveals() {
137
203
  this.$inputs.forEach($input => this.syncConditionalRevealWithInputState($input));
@@ -1 +1 @@
1
- {"version":3,"file":"checkboxes.bundle.mjs","sources":["../../../../src/govuk/errors/index.mjs","../../../../src/govuk/common/index.mjs","../../../../src/govuk/govuk-frontend-component.mjs","../../../../src/govuk/components/checkboxes/checkboxes.mjs"],"sourcesContent":["/**\n * GOV.UK Frontend error\n *\n * A base class for `Error`s thrown by GOV.UK Frontend.\n *\n * It is meant to be extended into specific types of errors\n * to be thrown by our code.\n *\n * @example\n * ```js\n * class MissingRootError extends GOVUKFrontendError {\n * // Setting an explicit name is important as extending the class will not\n * // set a new `name` on the subclass. The `name` property is important\n * // to ensure intelligible error names even if the class name gets\n * // mangled by a minifier\n * name = \"MissingRootError\"\n * }\n * ```\n * @abstract\n */\nexport class GOVUKFrontendError extends Error {\n name = 'GOVUKFrontendError'\n}\n\n/**\n * Indicates that GOV.UK Frontend is not supported\n */\nexport class SupportError extends GOVUKFrontendError {\n name = 'SupportError'\n\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 =\n 'noModule' in HTMLScriptElement.prototype\n ? 'GOV.UK Frontend initialised without `<body class=\"govuk-frontend-supported\">` from template `<script>` snippet'\n : 'GOV.UK Frontend is not supported in this browser'\n\n super(\n $scope\n ? supportMessage\n : 'GOV.UK Frontend initialised without `<script type=\"module\">`'\n )\n }\n}\n\n/**\n * Indicates that a component has received an illegal configuration\n */\nexport class ConfigError extends GOVUKFrontendError {\n name = 'ConfigError'\n}\n\n/**\n * Indicates an issue with an element (possibly `null` or `undefined`)\n */\nexport class ElementError extends GOVUKFrontendError {\n name = 'ElementError'\n\n /**\n * @internal\n * @overload\n * @param {string} message - Element error message\n */\n\n /**\n * @internal\n * @overload\n * @param {ElementErrorOptions} options - Element error options\n */\n\n /**\n * @internal\n * @param {string | ElementErrorOptions} messageOrOptions - Element error message or options\n */\n constructor(messageOrOptions) {\n let message = typeof messageOrOptions === 'string' ? messageOrOptions : ''\n\n // Build message from options\n if (typeof messageOrOptions === 'object') {\n const { componentName, identifier, element, expectedType } =\n messageOrOptions\n\n // Add prefix and identifier\n message = `${componentName}: ${identifier}`\n\n // Append reason\n message += element\n ? ` is not of type ${expectedType ?? 'HTMLElement'}`\n : ' not found'\n }\n\n super(message)\n }\n}\n\n/**\n * Element error options\n *\n * @internal\n * @typedef {object} ElementErrorOptions\n * @property {string} componentName - The name of the component throwing the error\n * @property {string} identifier - An identifier that'll let the user understand which element has an error. This is whatever makes the most sense\n * @property {Element | null} [element] - The element in error\n * @property {string} [expectedType] - The type that was expected for the identifier\n */\n","import { normaliseString } from './normalise-string.mjs'\n\n/**\n * Common helpers which do not require polyfill.\n *\n * IMPORTANT: If a helper require a polyfill, please isolate it in its own module\n * so that the polyfill can be properly tree-shaken and does not burden\n * the components that do not need that helper\n */\n\n/**\n * Config merging function\n *\n * Takes any number of objects and combines them together, with\n * greatest priority on the LAST item passed in.\n *\n * @internal\n * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge\n * @returns {{ [key: string]: unknown }} A merged config object\n */\nexport function mergeConfigs(...configObjects) {\n // Start with an empty object as our base\n /** @type {{ [key: string]: unknown }} */\n const formattedConfigObject = {}\n\n // Loop through each of the passed objects\n for (const configObject of configObjects) {\n for (const key of Object.keys(configObject)) {\n const option = formattedConfigObject[key]\n const override = configObject[key]\n\n // Push their keys one-by-one into formattedConfigObject. Any duplicate\n // keys with object values will be merged, otherwise the new value will\n // override the existing value.\n if (isObject(option) && isObject(override)) {\n // @ts-expect-error Index signature for type 'string' is missing\n formattedConfigObject[key] = mergeConfigs(option, override)\n } else {\n // Apply override\n formattedConfigObject[key] = override\n }\n }\n }\n\n return formattedConfigObject\n}\n\n/**\n * Extracts keys starting with a particular namespace from dataset ('data-*')\n * object, removing the namespace in the process, normalising all values\n *\n * @internal\n * @param {{ schema: Schema }} Component - Component class\n * @param {DOMStringMap} dataset - The object to extract key-value pairs from\n * @param {string} namespace - The namespace to filter keys with\n * @returns {ObjectNested | undefined} Nested object with dot-separated key namespace removed\n */\nexport function extractConfigByNamespace(Component, dataset, namespace) {\n const property = Component.schema.properties[namespace]\n\n // Only extract configs for object schema properties\n if (property?.type !== 'object') {\n return\n }\n\n // Add default empty config\n const newObject = {\n [namespace]: /** @type {ObjectNested} */ ({})\n }\n\n for (const [key, value] of Object.entries(dataset)) {\n /** @type {ObjectNested | ObjectNested[NestedKey]} */\n let current = newObject\n\n // Split the key into parts, using . as our namespace separator\n const keyParts = key.split('.')\n\n /**\n * Create new level per part\n *\n * e.g. 'i18n.textareaDescription.other' becomes\n * `{ i18n: { textareaDescription: { other } } }`\n */\n for (const [index, name] of keyParts.entries()) {\n if (typeof current === 'object') {\n // Drop down to nested object until the last part\n if (index < keyParts.length - 1) {\n // New nested object (optionally) replaces existing value\n if (!isObject(current[name])) {\n current[name] = {}\n }\n\n // Drop down into new or existing nested object\n current = current[name]\n } else if (key !== namespace) {\n // Normalised value (optionally) replaces existing value\n current[name] = normaliseString(value)\n }\n }\n }\n }\n\n return newObject[namespace]\n}\n\n/**\n * Get hash fragment from URL\n *\n * Extract the hash fragment (everything after the hash) from a URL,\n * but not including the hash symbol\n *\n * @private\n * @param {string} url - URL\n * @returns {string | undefined} Fragment from URL, without the hash\n */\nexport function getFragmentFromUrl(url) {\n if (!url.includes('#')) {\n return undefined\n }\n\n return url.split('#').pop()\n}\n\n/**\n * Get GOV.UK Frontend breakpoint value from CSS custom property\n *\n * @private\n * @param {string} name - Breakpoint name\n * @returns {{ property: string, value?: string }} Breakpoint object\n */\nexport function getBreakpoint(name) {\n const property = `--govuk-frontend-breakpoint-${name}`\n\n // Get value from `<html>` with breakpoints on CSS :root\n const value = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(property)\n\n return {\n property,\n value: value || undefined\n }\n}\n\n/**\n * Move focus to element\n *\n * Sets tabindex to -1 to make the element programmatically focusable,\n * but removes it on blur as the element doesn't need to be focused again.\n *\n * @private\n * @template {HTMLElement} FocusElement\n * @param {FocusElement} $element - HTML element\n * @param {object} [options] - Handler options\n * @param {function(this: FocusElement): void} [options.onBeforeFocus] - Callback before focus\n * @param {function(this: FocusElement): void} [options.onBlur] - Callback on blur\n */\nexport function setFocus($element, options = {}) {\n const isFocusable = $element.getAttribute('tabindex')\n\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1')\n }\n\n /**\n * Handle element focus\n */\n function onFocus() {\n $element.addEventListener('blur', onBlur, { once: true })\n }\n\n /**\n * Handle element blur\n */\n function onBlur() {\n options.onBlur?.call($element)\n\n if (!isFocusable) {\n $element.removeAttribute('tabindex')\n }\n }\n\n // Add listener to reset element on blur, after focus\n $element.addEventListener('focus', onFocus, { once: true })\n\n // Focus element\n options.onBeforeFocus?.call($element)\n $element.focus()\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 * @internal\n * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support\n * @returns {boolean} Whether GOV.UK Frontend is supported on this page\n */\nexport function isSupported($scope = document.body) {\n if (!$scope) {\n return false\n }\n\n return $scope.classList.contains('govuk-frontend-supported')\n}\n\n/**\n * Validate component config by schema\n *\n * Follows limited examples in JSON schema for wider support in future\n *\n * {@link https://ajv.js.org/json-schema.html#compound-keywords}\n * {@link https://ajv.js.org/packages/ajv-errors.html#single-message}\n *\n * @internal\n * @param {Schema} schema - Config schema\n * @param {{ [key: string]: unknown }} config - Component config\n * @returns {string[]} List of validation errors\n */\nexport function validateConfig(schema, config) {\n const validationErrors = []\n\n // Check errors for each schema\n for (const [name, conditions] of Object.entries(schema)) {\n const errors = []\n\n // Check errors for each schema condition\n if (Array.isArray(conditions)) {\n for (const { required, errorMessage } of conditions) {\n if (!required.every((key) => !!config[key])) {\n errors.push(errorMessage) // Missing config key value\n }\n }\n\n // Check one condition passes or add errors\n if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {\n validationErrors.push(...errors)\n }\n }\n }\n\n return validationErrors\n}\n\n/**\n * Check for an array\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an array\n */\nfunction isArray(option) {\n return Array.isArray(option)\n}\n\n/**\n * Check for an object\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an object\n */\nfunction isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option)\n}\n\n/**\n * Schema for component config\n *\n * @typedef {object} Schema\n * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties\n * @property {SchemaCondition[]} [anyOf] - List of schema conditions\n */\n\n/**\n * Schema property for component config\n *\n * @typedef {object} SchemaProperty\n * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type\n */\n\n/**\n * Schema condition for component config\n *\n * @typedef {object} SchemaCondition\n * @property {string[]} required - List of required config fields\n * @property {string} errorMessage - Error message when required config fields not provided\n */\n\n/**\n * @internal\n * @typedef {keyof ObjectNested} NestedKey\n * @typedef {{ [key: string]: string | boolean | number | ObjectNested | undefined }} ObjectNested\n */\n","import { isSupported } from './common/index.mjs'\nimport { SupportError } from './errors/index.mjs'\n\n/**\n * Base Component class\n *\n * Centralises the behaviours shared by our components\n *\n * @internal\n * @abstract\n */\nexport class GOVUKFrontendComponent {\n /**\n * Constructs a new component, validating that GOV.UK Frontend is supported\n *\n * @internal\n */\n constructor() {\n this.checkSupport()\n }\n\n /**\n * Validates whether GOV.UK Frontend is supported\n *\n * @private\n * @throws {SupportError} when GOV.UK Frontend is not supported\n */\n checkSupport() {\n if (!isSupported()) {\n throw new SupportError()\n }\n }\n}\n","import { ElementError } from '../../errors/index.mjs'\nimport { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'\n\n/**\n * Checkboxes component\n *\n * @preserve\n */\nexport class Checkboxes extends GOVUKFrontendComponent {\n /** @private */\n $module\n\n /** @private */\n $inputs\n\n /**\n * Checkboxes can be associated with a 'conditionally revealed' content block\n * – for example, a checkbox for 'Phone' could reveal an additional form field\n * for the user to enter their phone number.\n *\n * These associations are made using a `data-aria-controls` attribute, which\n * is promoted to an aria-controls attribute during initialisation.\n *\n * We also need to restore the state of any conditional reveals on the page\n * (for example if the user has navigated back), and set up event handlers to\n * keep the reveal in sync with the checkbox state.\n *\n * @param {Element | null} $module - HTML element to use for checkboxes\n */\n constructor($module) {\n super()\n\n if (!($module instanceof HTMLElement)) {\n throw new ElementError({\n componentName: 'Checkboxes',\n element: $module,\n identifier: 'Root element (`$module`)'\n })\n }\n\n const $inputs = $module.querySelectorAll('input[type=\"checkbox\"]')\n if (!$inputs.length) {\n throw new ElementError({\n componentName: 'Checkboxes',\n identifier: 'Form inputs (`<input type=\"checkbox\">`)'\n })\n }\n\n this.$module = $module\n this.$inputs = $inputs\n\n this.$inputs.forEach(($input) => {\n const targetId = $input.getAttribute('data-aria-controls')\n\n // Skip radios without data-aria-controls attributes\n if (!targetId) {\n return\n }\n\n // Throw if target conditional element does not exist.\n if (!document.getElementById(targetId)) {\n throw new ElementError({\n componentName: 'Checkboxes',\n identifier: `Conditional reveal (\\`id=\"${targetId}\"\\`)`\n })\n }\n\n // Promote the data-aria-controls attribute to a aria-controls attribute\n // so that the relationship is exposed in the AOM\n $input.setAttribute('aria-controls', targetId)\n $input.removeAttribute('data-aria-controls')\n })\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.syncAllConditionalReveals())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so sync now too.\n this.syncAllConditionalReveals()\n\n // Handle events\n this.$module.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Sync the conditional reveal states for all checkboxes in this $module.\n *\n * @private\n */\n syncAllConditionalReveals() {\n this.$inputs.forEach(($input) =>\n this.syncConditionalRevealWithInputState($input)\n )\n }\n\n /**\n * Sync conditional reveal with the input state\n *\n * Synchronise the visibility of the conditional reveal, and its accessible\n * state, with the input's checked state.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n syncConditionalRevealWithInputState($input) {\n const targetId = $input.getAttribute('aria-controls')\n if (!targetId) {\n return\n }\n\n const $target = document.getElementById(targetId)\n if ($target?.classList.contains('govuk-checkboxes__conditional')) {\n const inputIsChecked = $input.checked\n\n $input.setAttribute('aria-expanded', inputIsChecked.toString())\n $target.classList.toggle(\n 'govuk-checkboxes__conditional--hidden',\n !inputIsChecked\n )\n }\n }\n\n /**\n * Uncheck other checkboxes\n *\n * Find any other checkbox inputs with the same name value, and uncheck them.\n * This is useful for when a “None of these\" checkbox is checked.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckAllInputsExcept($input) {\n const allInputsWithSameName = document.querySelectorAll(\n `input[type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameName.forEach(($inputWithSameName) => {\n const hasSameFormOwner = $input.form === $inputWithSameName.form\n if (hasSameFormOwner && $inputWithSameName !== $input) {\n $inputWithSameName.checked = false\n this.syncConditionalRevealWithInputState($inputWithSameName)\n }\n })\n }\n\n /**\n * Uncheck exclusive checkboxes\n *\n * Find any checkbox inputs with the same name value and the 'exclusive'\n * behaviour, and uncheck them. This helps prevent someone checking both a\n * regular checkbox and a \"None of these\" checkbox in the same fieldset.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckExclusiveInputs($input) {\n const allInputsWithSameNameAndExclusiveBehaviour =\n document.querySelectorAll(\n `input[data-behaviour=\"exclusive\"][type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameNameAndExclusiveBehaviour.forEach(($exclusiveInput) => {\n const hasSameFormOwner = $input.form === $exclusiveInput.form\n if (hasSameFormOwner) {\n $exclusiveInput.checked = false\n this.syncConditionalRevealWithInputState($exclusiveInput)\n }\n })\n }\n\n /**\n * Click event handler\n *\n * Handle a click within the $module – if the click occurred on a checkbox,\n * sync the state of any associated conditional reveal with the checkbox\n * state.\n *\n * @private\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $clickedInput = event.target\n\n // Ignore clicks on things that aren't checkbox inputs\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'checkbox'\n ) {\n return\n }\n\n // If the checkbox conditionally-reveals some content, sync the state\n const hasAriaControls = $clickedInput.getAttribute('aria-controls')\n if (hasAriaControls) {\n this.syncConditionalRevealWithInputState($clickedInput)\n }\n\n // No further behaviour needed for unchecking\n if (!$clickedInput.checked) {\n return\n }\n\n // Handle 'exclusive' checkbox behaviour (ie \"None of these\")\n const hasBehaviourExclusive =\n $clickedInput.getAttribute('data-behaviour') === 'exclusive'\n if (hasBehaviourExclusive) {\n this.unCheckAllInputsExcept($clickedInput)\n } else {\n this.unCheckExclusiveInputs($clickedInput)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-checkboxes'\n}\n"],"names":["GOVUKFrontendError","Error","constructor","args","name","SupportError","$scope","document","body","supportMessage","HTMLScriptElement","prototype","ElementError","messageOrOptions","message","componentName","identifier","element","expectedType","isSupported","classList","contains","GOVUKFrontendComponent","checkSupport","Checkboxes","$module","$inputs","HTMLElement","querySelectorAll","length","forEach","$input","targetId","getAttribute","getElementById","setAttribute","removeAttribute","window","addEventListener","syncAllConditionalReveals","event","handleClick","syncConditionalRevealWithInputState","$target","inputIsChecked","checked","toString","toggle","unCheckAllInputsExcept","allInputsWithSameName","$inputWithSameName","hasSameFormOwner","form","unCheckExclusiveInputs","allInputsWithSameNameAndExclusiveBehaviour","$exclusiveInput","$clickedInput","target","HTMLInputElement","type","hasAriaControls","hasBehaviourExclusive","moduleName"],"mappings":"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"}
1
+ {"version":3,"file":"checkboxes.bundle.mjs","sources":["../../../../src/govuk/common/index.mjs","../../../../src/govuk/errors/index.mjs","../../../../src/govuk/govuk-frontend-component.mjs","../../../../src/govuk/components/checkboxes/checkboxes.mjs"],"sourcesContent":["import { normaliseString } from './normalise-string.mjs'\n\n/**\n * Common helpers which do not require polyfill.\n *\n * IMPORTANT: If a helper require a polyfill, please isolate it in its own module\n * so that the polyfill can be properly tree-shaken and does not burden\n * the components that do not need that helper\n */\n\n/**\n * Config merging function\n *\n * Takes any number of objects and combines them together, with\n * greatest priority on the LAST item passed in.\n *\n * @internal\n * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge\n * @returns {{ [key: string]: unknown }} A merged config object\n */\nexport function mergeConfigs(...configObjects) {\n // Start with an empty object as our base\n /** @type {{ [key: string]: unknown }} */\n const formattedConfigObject = {}\n\n // Loop through each of the passed objects\n for (const configObject of configObjects) {\n for (const key of Object.keys(configObject)) {\n const option = formattedConfigObject[key]\n const override = configObject[key]\n\n // Push their keys one-by-one into formattedConfigObject. Any duplicate\n // keys with object values will be merged, otherwise the new value will\n // override the existing value.\n if (isObject(option) && isObject(override)) {\n // @ts-expect-error Index signature for type 'string' is missing\n formattedConfigObject[key] = mergeConfigs(option, override)\n } else {\n // Apply override\n formattedConfigObject[key] = override\n }\n }\n }\n\n return formattedConfigObject\n}\n\n/**\n * Extracts keys starting with a particular namespace from dataset ('data-*')\n * object, removing the namespace in the process, normalising all values\n *\n * @internal\n * @param {{ schema: Schema }} Component - Component class\n * @param {DOMStringMap} dataset - The object to extract key-value pairs from\n * @param {string} namespace - The namespace to filter keys with\n * @returns {ObjectNested | undefined} Nested object with dot-separated key namespace removed\n */\nexport function extractConfigByNamespace(Component, dataset, namespace) {\n const property = Component.schema.properties[namespace]\n\n // Only extract configs for object schema properties\n if (property?.type !== 'object') {\n return\n }\n\n // Add default empty config\n const newObject = {\n [namespace]: /** @type {ObjectNested} */ ({})\n }\n\n for (const [key, value] of Object.entries(dataset)) {\n /** @type {ObjectNested | ObjectNested[NestedKey]} */\n let current = newObject\n\n // Split the key into parts, using . as our namespace separator\n const keyParts = key.split('.')\n\n /**\n * Create new level per part\n *\n * e.g. 'i18n.textareaDescription.other' becomes\n * `{ i18n: { textareaDescription: { other } } }`\n */\n for (const [index, name] of keyParts.entries()) {\n if (typeof current === 'object') {\n // Drop down to nested object until the last part\n if (index < keyParts.length - 1) {\n // New nested object (optionally) replaces existing value\n if (!isObject(current[name])) {\n current[name] = {}\n }\n\n // Drop down into new or existing nested object\n current = current[name]\n } else if (key !== namespace) {\n // Normalised value (optionally) replaces existing value\n current[name] = normaliseString(value)\n }\n }\n }\n }\n\n return newObject[namespace]\n}\n\n/**\n * Get hash fragment from URL\n *\n * Extract the hash fragment (everything after the hash) from a URL,\n * but not including the hash symbol\n *\n * @private\n * @param {string} url - URL\n * @returns {string | undefined} Fragment from URL, without the hash\n */\nexport function getFragmentFromUrl(url) {\n if (!url.includes('#')) {\n return undefined\n }\n\n return url.split('#').pop()\n}\n\n/**\n * Get GOV.UK Frontend breakpoint value from CSS custom property\n *\n * @private\n * @param {string} name - Breakpoint name\n * @returns {{ property: string, value?: string }} Breakpoint object\n */\nexport function getBreakpoint(name) {\n const property = `--govuk-frontend-breakpoint-${name}`\n\n // Get value from `<html>` with breakpoints on CSS :root\n const value = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(property)\n\n return {\n property,\n value: value || undefined\n }\n}\n\n/**\n * Move focus to element\n *\n * Sets tabindex to -1 to make the element programmatically focusable,\n * but removes it on blur as the element doesn't need to be focused again.\n *\n * @private\n * @template {HTMLElement} FocusElement\n * @param {FocusElement} $element - HTML element\n * @param {object} [options] - Handler options\n * @param {function(this: FocusElement): void} [options.onBeforeFocus] - Callback before focus\n * @param {function(this: FocusElement): void} [options.onBlur] - Callback on blur\n */\nexport function setFocus($element, options = {}) {\n const isFocusable = $element.getAttribute('tabindex')\n\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1')\n }\n\n /**\n * Handle element focus\n */\n function onFocus() {\n $element.addEventListener('blur', onBlur, { once: true })\n }\n\n /**\n * Handle element blur\n */\n function onBlur() {\n options.onBlur?.call($element)\n\n if (!isFocusable) {\n $element.removeAttribute('tabindex')\n }\n }\n\n // Add listener to reset element on blur, after focus\n $element.addEventListener('focus', onFocus, { once: true })\n\n // Focus element\n options.onBeforeFocus?.call($element)\n $element.focus()\n}\n\n/**\n * Checks if component is already initialised\n *\n * @internal\n * @param {Element} $root - HTML element to be checked\n * @param {string} moduleName - name of component module\n * @returns {boolean} Whether component is already initialised\n */\nexport function isInitialised($root, moduleName) {\n return (\n $root instanceof HTMLElement &&\n $root.hasAttribute(`data-${moduleName}-init`)\n )\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 */\nexport function isSupported($scope = document.body) {\n if (!$scope) {\n return false\n }\n\n return $scope.classList.contains('govuk-frontend-supported')\n}\n\n/**\n * Validate component config by schema\n *\n * Follows limited examples in JSON schema for wider support in future\n *\n * {@link https://ajv.js.org/json-schema.html#compound-keywords}\n * {@link https://ajv.js.org/packages/ajv-errors.html#single-message}\n *\n * @internal\n * @param {Schema} schema - Config schema\n * @param {{ [key: string]: unknown }} config - Component config\n * @returns {string[]} List of validation errors\n */\nexport function validateConfig(schema, config) {\n const validationErrors = []\n\n // Check errors for each schema\n for (const [name, conditions] of Object.entries(schema)) {\n const errors = []\n\n // Check errors for each schema condition\n if (Array.isArray(conditions)) {\n for (const { required, errorMessage } of conditions) {\n if (!required.every((key) => !!config[key])) {\n errors.push(errorMessage) // Missing config key value\n }\n }\n\n // Check one condition passes or add errors\n if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {\n validationErrors.push(...errors)\n }\n }\n }\n\n return validationErrors\n}\n\n/**\n * Check for an array\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an array\n */\nfunction isArray(option) {\n return Array.isArray(option)\n}\n\n/**\n * Check for an object\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an object\n */\nfunction isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option)\n}\n\n/**\n * Format error message\n *\n * @internal\n * @param {ComponentWithModuleName} Component - Component that threw the error\n * @param {string} message - Error message\n * @returns {string} - Formatted error message\n */\nexport function formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`\n}\n\n/**\n * Schema for component config\n *\n * @typedef {object} Schema\n * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties\n * @property {SchemaCondition[]} [anyOf] - List of schema conditions\n */\n\n/**\n * Schema property for component config\n *\n * @typedef {object} SchemaProperty\n * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type\n */\n\n/**\n * Schema condition for component config\n *\n * @typedef {object} SchemaCondition\n * @property {string[]} required - List of required config fields\n * @property {string} errorMessage - Error message when required config fields not provided\n */\n\n/**\n * @internal\n * @typedef {keyof ObjectNested} NestedKey\n * @typedef {{ [key: string]: string | boolean | number | ObjectNested | undefined }} ObjectNested\n */\n\n/* eslint-disable jsdoc/valid-types --\n * `{new(...args: any[] ): object}` is not recognised as valid\n * https://github.com/gajus/eslint-plugin-jsdoc/issues/145#issuecomment-1308722878\n * https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/131\n **/\n\n/**\n * @typedef ComponentWithModuleName\n * @property {string} moduleName - Name of the component\n */\n\n/* eslint-enable jsdoc/valid-types */\n","import { formatErrorMessage } from '../common/index.mjs'\n\n/**\n * GOV.UK Frontend error\n *\n * A base class for `Error`s thrown by GOV.UK Frontend.\n *\n * It is meant to be extended into specific types of errors\n * to be thrown by our code.\n *\n * @example\n * ```js\n * class MissingRootError extends GOVUKFrontendError {\n * // Setting an explicit name is important as extending the class will not\n * // set a new `name` on the subclass. The `name` property is important\n * // to ensure intelligible error names even if the class name gets\n * // mangled by a minifier\n * name = \"MissingRootError\"\n * }\n * ```\n * @virtual\n */\nexport class GOVUKFrontendError extends Error {\n name = 'GOVUKFrontendError'\n}\n\n/**\n * Indicates that GOV.UK Frontend is not supported\n */\nexport class SupportError extends GOVUKFrontendError {\n name = 'SupportError'\n\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 =\n 'noModule' in HTMLScriptElement.prototype\n ? 'GOV.UK Frontend initialised without `<body class=\"govuk-frontend-supported\">` from template `<script>` snippet'\n : 'GOV.UK Frontend is not supported in this browser'\n\n super(\n $scope\n ? supportMessage\n : 'GOV.UK Frontend initialised without `<script type=\"module\">`'\n )\n }\n}\n\n/**\n * Indicates that a component has received an illegal configuration\n */\nexport class ConfigError extends GOVUKFrontendError {\n name = 'ConfigError'\n}\n\n/**\n * Indicates an issue with an element (possibly `null` or `undefined`)\n */\nexport class ElementError extends GOVUKFrontendError {\n name = 'ElementError'\n\n /**\n * @internal\n * @overload\n * @param {string} message - Element error message\n */\n\n /**\n * @internal\n * @overload\n * @param {ElementErrorOptions} options - Element error options\n */\n\n /**\n * @internal\n * @param {string | ElementErrorOptions} messageOrOptions - Element error message or options\n */\n constructor(messageOrOptions) {\n let message = typeof messageOrOptions === 'string' ? messageOrOptions : ''\n\n // Build message from options\n if (typeof messageOrOptions === 'object') {\n const { component, identifier, element, expectedType } = messageOrOptions\n\n message = identifier\n\n // Append reason\n message += element\n ? ` is not of type ${expectedType ?? 'HTMLElement'}`\n : ' not found'\n\n message = formatErrorMessage(component, message)\n }\n\n super(message)\n }\n}\n\n/**\n * Indicates that a component is already initialised\n */\nexport class InitError extends GOVUKFrontendError {\n name = 'InitError'\n\n /**\n * @internal\n * @param {ComponentWithModuleName | string} componentOrMessage - name of the component module\n */\n constructor(componentOrMessage) {\n const message =\n typeof componentOrMessage === 'string'\n ? componentOrMessage\n : formatErrorMessage(\n componentOrMessage,\n `Root element (\\`$root\\`) already initialised`\n )\n\n super(message)\n }\n}\n\n/**\n * Element error options\n *\n * @internal\n * @typedef {object} ElementErrorOptions\n * @property {string} identifier - An identifier that'll let the user understand which element has an error. This is whatever makes the most sense\n * @property {Element | null} [element] - The element in error\n * @property {string} [expectedType] - The type that was expected for the identifier\n * @property {ComponentWithModuleName} component - Component throwing the error\n */\n\n/**\n * @typedef {import('../common/index.mjs').ComponentWithModuleName} ComponentWithModuleName\n */\n","import { isInitialised, isSupported } from './common/index.mjs'\nimport { ElementError, InitError, SupportError } from './errors/index.mjs'\n\n/**\n * Base Component class\n *\n * Centralises the behaviours shared by our components\n *\n * @virtual\n * @template {Element} [RootElementType=HTMLElement]\n */\nexport class GOVUKFrontendComponent {\n /**\n * @type {typeof Element}\n */\n static elementType = HTMLElement\n\n // allows Typescript user to work around the lack of types\n // in GOVUKFrontend package, Typescript is not aware of $root\n // in components that extend GOVUKFrontendComponent\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\n /**\n * @protected\n * @type {RootElementType}\n */\n _$root\n\n /**\n * Constructs a new component, validating that GOV.UK Frontend is supported\n *\n * @internal\n * @param {Element | null} [$root] - HTML element to use for component\n */\n constructor($root) {\n const childConstructor = /** @type {ChildClassConstructor} */ (\n this.constructor\n )\n\n // TypeScript does not enforce that inheriting classes will define a `moduleName`\n // (even if we add a `@virtual` `static moduleName` property to this class).\n // While we trust users to do this correctly, we do a little check to provide them\n // a helpful error message.\n //\n // After this, we'll be sure that `childConstructor` has a `moduleName`\n // as expected of the `ChildClassConstructor` we've cast `this.constructor` to.\n if (typeof childConstructor.moduleName !== 'string') {\n throw new InitError(`\\`moduleName\\` not defined in component`)\n }\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 = /** @type {RootElementType} */ ($root)\n }\n\n childConstructor.checkSupport()\n\n this.checkInitialised()\n\n const moduleName = childConstructor.moduleName\n\n this.$root.setAttribute(`data-${moduleName}-init`, '')\n }\n\n /**\n * Validates whether component is already initialised\n *\n * @private\n * @throws {InitError} when component is already initialised\n */\n checkInitialised() {\n const constructor = /** @type {ChildClassConstructor} */ (this.constructor)\n const moduleName = constructor.moduleName\n\n if (moduleName && isInitialised(this.$root, moduleName)) {\n throw new InitError(constructor)\n }\n }\n\n /**\n * Validates whether components are supported\n *\n * @throws {SupportError} when the components are not supported\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 GOVUKFrontendComponent & ChildClass} ChildClassConstructor\n */\n","import { ElementError } from '../../errors/index.mjs'\nimport { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'\n\n/**\n * Checkboxes component\n *\n * @preserve\n */\nexport class Checkboxes extends GOVUKFrontendComponent {\n /** @private */\n $inputs\n\n /**\n * Checkboxes can be associated with a 'conditionally revealed' content block\n * – for example, a checkbox for 'Phone' could reveal an additional form field\n * for the user to enter their phone number.\n *\n * These associations are made using a `data-aria-controls` attribute, which\n * is promoted to an aria-controls attribute during initialisation.\n *\n * We also need to restore the state of any conditional reveals on the page\n * (for example if the user has navigated back), and set up event handlers to\n * keep the reveal in sync with the checkbox state.\n *\n * @param {Element | null} $root - HTML element to use for checkboxes\n */\n constructor($root) {\n super($root)\n\n const $inputs = this.$root.querySelectorAll('input[type=\"checkbox\"]')\n if (!$inputs.length) {\n throw new ElementError({\n component: Checkboxes,\n identifier: 'Form inputs (`<input type=\"checkbox\">`)'\n })\n }\n\n this.$inputs = $inputs\n\n this.$inputs.forEach(($input) => {\n const targetId = $input.getAttribute('data-aria-controls')\n\n // Skip radios without data-aria-controls attributes\n if (!targetId) {\n return\n }\n\n // Throw if target conditional element does not exist.\n if (!document.getElementById(targetId)) {\n throw new ElementError({\n component: Checkboxes,\n identifier: `Conditional reveal (\\`id=\"${targetId}\"\\`)`\n })\n }\n\n // Promote the data-aria-controls attribute to a aria-controls attribute\n // so that the relationship is exposed in the AOM\n $input.setAttribute('aria-controls', targetId)\n $input.removeAttribute('data-aria-controls')\n })\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.syncAllConditionalReveals())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so sync now too.\n this.syncAllConditionalReveals()\n\n // Handle events\n this.$root.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Sync the conditional reveal states for all checkboxes in this component.\n *\n * @private\n */\n syncAllConditionalReveals() {\n this.$inputs.forEach(($input) =>\n this.syncConditionalRevealWithInputState($input)\n )\n }\n\n /**\n * Sync conditional reveal with the input state\n *\n * Synchronise the visibility of the conditional reveal, and its accessible\n * state, with the input's checked state.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n syncConditionalRevealWithInputState($input) {\n const targetId = $input.getAttribute('aria-controls')\n if (!targetId) {\n return\n }\n\n const $target = document.getElementById(targetId)\n if ($target?.classList.contains('govuk-checkboxes__conditional')) {\n const inputIsChecked = $input.checked\n\n $input.setAttribute('aria-expanded', inputIsChecked.toString())\n $target.classList.toggle(\n 'govuk-checkboxes__conditional--hidden',\n !inputIsChecked\n )\n }\n }\n\n /**\n * Uncheck other checkboxes\n *\n * Find any other checkbox inputs with the same name value, and uncheck them.\n * This is useful for when a “None of these\" checkbox is checked.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckAllInputsExcept($input) {\n const allInputsWithSameName = document.querySelectorAll(\n `input[type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameName.forEach(($inputWithSameName) => {\n const hasSameFormOwner = $input.form === $inputWithSameName.form\n if (hasSameFormOwner && $inputWithSameName !== $input) {\n $inputWithSameName.checked = false\n this.syncConditionalRevealWithInputState($inputWithSameName)\n }\n })\n }\n\n /**\n * Uncheck exclusive checkboxes\n *\n * Find any checkbox inputs with the same name value and the 'exclusive'\n * behaviour, and uncheck them. This helps prevent someone checking both a\n * regular checkbox and a \"None of these\" checkbox in the same fieldset.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckExclusiveInputs($input) {\n const allInputsWithSameNameAndExclusiveBehaviour =\n document.querySelectorAll(\n `input[data-behaviour=\"exclusive\"][type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameNameAndExclusiveBehaviour.forEach(($exclusiveInput) => {\n const hasSameFormOwner = $input.form === $exclusiveInput.form\n if (hasSameFormOwner) {\n $exclusiveInput.checked = false\n this.syncConditionalRevealWithInputState($exclusiveInput)\n }\n })\n }\n\n /**\n * Click event handler\n *\n * Handle a click within the component root – if the click occurred on a checkbox,\n * sync the state of any associated conditional reveal with the checkbox\n * state.\n *\n * @private\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $clickedInput = event.target\n\n // Ignore clicks on things that aren't checkbox inputs\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'checkbox'\n ) {\n return\n }\n\n // If the checkbox conditionally-reveals some content, sync the state\n const hasAriaControls = $clickedInput.getAttribute('aria-controls')\n if (hasAriaControls) {\n this.syncConditionalRevealWithInputState($clickedInput)\n }\n\n // No further behaviour needed for unchecking\n if (!$clickedInput.checked) {\n return\n }\n\n // Handle 'exclusive' checkbox behaviour (ie \"None of these\")\n const hasBehaviourExclusive =\n $clickedInput.getAttribute('data-behaviour') === 'exclusive'\n if (hasBehaviourExclusive) {\n this.unCheckAllInputsExcept($clickedInput)\n } else {\n this.unCheckExclusiveInputs($clickedInput)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-checkboxes'\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","GOVUKFrontendComponent","_$root","childConstructor","elementType","checkSupport","checkInitialised","setAttribute","Checkboxes","$inputs","querySelectorAll","length","forEach","$input","targetId","getAttribute","getElementById","removeAttribute","window","addEventListener","syncAllConditionalReveals","event","handleClick","syncConditionalRevealWithInputState","$target","inputIsChecked","checked","toString","toggle","unCheckAllInputsExcept","allInputsWithSameName","$inputWithSameName","hasSameFormOwner","form","unCheckExclusiveInputs","allInputsWithSameNameAndExclusiveBehaviour","$exclusiveInput","$clickedInput","target","HTMLInputElement","type","hasAriaControls","hasBehaviourExclusive"],"mappings":"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"}
@@ -19,27 +19,18 @@ class Checkboxes extends GOVUKFrontendComponent {
19
19
  * (for example if the user has navigated back), and set up event handlers to
20
20
  * keep the reveal in sync with the checkbox state.
21
21
  *
22
- * @param {Element | null} $module - HTML element to use for checkboxes
22
+ * @param {Element | null} $root - HTML element to use for checkboxes
23
23
  */
24
- constructor($module) {
25
- super();
26
- this.$module = void 0;
24
+ constructor($root) {
25
+ super($root);
27
26
  this.$inputs = void 0;
28
- if (!($module instanceof HTMLElement)) {
29
- throw new ElementError({
30
- componentName: 'Checkboxes',
31
- element: $module,
32
- identifier: 'Root element (`$module`)'
33
- });
34
- }
35
- const $inputs = $module.querySelectorAll('input[type="checkbox"]');
27
+ const $inputs = this.$root.querySelectorAll('input[type="checkbox"]');
36
28
  if (!$inputs.length) {
37
29
  throw new ElementError({
38
- componentName: 'Checkboxes',
30
+ component: Checkboxes,
39
31
  identifier: 'Form inputs (`<input type="checkbox">`)'
40
32
  });
41
33
  }
42
- this.$module = $module;
43
34
  this.$inputs = $inputs;
44
35
  this.$inputs.forEach($input => {
45
36
  const targetId = $input.getAttribute('data-aria-controls');
@@ -48,7 +39,7 @@ class Checkboxes extends GOVUKFrontendComponent {
48
39
  }
49
40
  if (!document.getElementById(targetId)) {
50
41
  throw new ElementError({
51
- componentName: 'Checkboxes',
42
+ component: Checkboxes,
52
43
  identifier: `Conditional reveal (\`id="${targetId}"\`)`
53
44
  });
54
45
  }
@@ -57,7 +48,7 @@ class Checkboxes extends GOVUKFrontendComponent {
57
48
  });
58
49
  window.addEventListener('pageshow', () => this.syncAllConditionalReveals());
59
50
  this.syncAllConditionalReveals();
60
- this.$module.addEventListener('click', event => this.handleClick(event));
51
+ this.$root.addEventListener('click', event => this.handleClick(event));
61
52
  }
62
53
  syncAllConditionalReveals() {
63
54
  this.$inputs.forEach($input => this.syncConditionalRevealWithInputState($input));
@@ -1 +1 @@
1
- {"version":3,"file":"checkboxes.mjs","sources":["../../../../src/govuk/components/checkboxes/checkboxes.mjs"],"sourcesContent":["import { ElementError } from '../../errors/index.mjs'\nimport { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'\n\n/**\n * Checkboxes component\n *\n * @preserve\n */\nexport class Checkboxes extends GOVUKFrontendComponent {\n /** @private */\n $module\n\n /** @private */\n $inputs\n\n /**\n * Checkboxes can be associated with a 'conditionally revealed' content block\n * – for example, a checkbox for 'Phone' could reveal an additional form field\n * for the user to enter their phone number.\n *\n * These associations are made using a `data-aria-controls` attribute, which\n * is promoted to an aria-controls attribute during initialisation.\n *\n * We also need to restore the state of any conditional reveals on the page\n * (for example if the user has navigated back), and set up event handlers to\n * keep the reveal in sync with the checkbox state.\n *\n * @param {Element | null} $module - HTML element to use for checkboxes\n */\n constructor($module) {\n super()\n\n if (!($module instanceof HTMLElement)) {\n throw new ElementError({\n componentName: 'Checkboxes',\n element: $module,\n identifier: 'Root element (`$module`)'\n })\n }\n\n const $inputs = $module.querySelectorAll('input[type=\"checkbox\"]')\n if (!$inputs.length) {\n throw new ElementError({\n componentName: 'Checkboxes',\n identifier: 'Form inputs (`<input type=\"checkbox\">`)'\n })\n }\n\n this.$module = $module\n this.$inputs = $inputs\n\n this.$inputs.forEach(($input) => {\n const targetId = $input.getAttribute('data-aria-controls')\n\n // Skip radios without data-aria-controls attributes\n if (!targetId) {\n return\n }\n\n // Throw if target conditional element does not exist.\n if (!document.getElementById(targetId)) {\n throw new ElementError({\n componentName: 'Checkboxes',\n identifier: `Conditional reveal (\\`id=\"${targetId}\"\\`)`\n })\n }\n\n // Promote the data-aria-controls attribute to a aria-controls attribute\n // so that the relationship is exposed in the AOM\n $input.setAttribute('aria-controls', targetId)\n $input.removeAttribute('data-aria-controls')\n })\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.syncAllConditionalReveals())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so sync now too.\n this.syncAllConditionalReveals()\n\n // Handle events\n this.$module.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Sync the conditional reveal states for all checkboxes in this $module.\n *\n * @private\n */\n syncAllConditionalReveals() {\n this.$inputs.forEach(($input) =>\n this.syncConditionalRevealWithInputState($input)\n )\n }\n\n /**\n * Sync conditional reveal with the input state\n *\n * Synchronise the visibility of the conditional reveal, and its accessible\n * state, with the input's checked state.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n syncConditionalRevealWithInputState($input) {\n const targetId = $input.getAttribute('aria-controls')\n if (!targetId) {\n return\n }\n\n const $target = document.getElementById(targetId)\n if ($target?.classList.contains('govuk-checkboxes__conditional')) {\n const inputIsChecked = $input.checked\n\n $input.setAttribute('aria-expanded', inputIsChecked.toString())\n $target.classList.toggle(\n 'govuk-checkboxes__conditional--hidden',\n !inputIsChecked\n )\n }\n }\n\n /**\n * Uncheck other checkboxes\n *\n * Find any other checkbox inputs with the same name value, and uncheck them.\n * This is useful for when a “None of these\" checkbox is checked.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckAllInputsExcept($input) {\n const allInputsWithSameName = document.querySelectorAll(\n `input[type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameName.forEach(($inputWithSameName) => {\n const hasSameFormOwner = $input.form === $inputWithSameName.form\n if (hasSameFormOwner && $inputWithSameName !== $input) {\n $inputWithSameName.checked = false\n this.syncConditionalRevealWithInputState($inputWithSameName)\n }\n })\n }\n\n /**\n * Uncheck exclusive checkboxes\n *\n * Find any checkbox inputs with the same name value and the 'exclusive'\n * behaviour, and uncheck them. This helps prevent someone checking both a\n * regular checkbox and a \"None of these\" checkbox in the same fieldset.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckExclusiveInputs($input) {\n const allInputsWithSameNameAndExclusiveBehaviour =\n document.querySelectorAll(\n `input[data-behaviour=\"exclusive\"][type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameNameAndExclusiveBehaviour.forEach(($exclusiveInput) => {\n const hasSameFormOwner = $input.form === $exclusiveInput.form\n if (hasSameFormOwner) {\n $exclusiveInput.checked = false\n this.syncConditionalRevealWithInputState($exclusiveInput)\n }\n })\n }\n\n /**\n * Click event handler\n *\n * Handle a click within the $module – if the click occurred on a checkbox,\n * sync the state of any associated conditional reveal with the checkbox\n * state.\n *\n * @private\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $clickedInput = event.target\n\n // Ignore clicks on things that aren't checkbox inputs\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'checkbox'\n ) {\n return\n }\n\n // If the checkbox conditionally-reveals some content, sync the state\n const hasAriaControls = $clickedInput.getAttribute('aria-controls')\n if (hasAriaControls) {\n this.syncConditionalRevealWithInputState($clickedInput)\n }\n\n // No further behaviour needed for unchecking\n if (!$clickedInput.checked) {\n return\n }\n\n // Handle 'exclusive' checkbox behaviour (ie \"None of these\")\n const hasBehaviourExclusive =\n $clickedInput.getAttribute('data-behaviour') === 'exclusive'\n if (hasBehaviourExclusive) {\n this.unCheckAllInputsExcept($clickedInput)\n } else {\n this.unCheckExclusiveInputs($clickedInput)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-checkboxes'\n}\n"],"names":["Checkboxes","GOVUKFrontendComponent","constructor","$module","$inputs","HTMLElement","ElementError","componentName","element","identifier","querySelectorAll","length","forEach","$input","targetId","getAttribute","document","getElementById","setAttribute","removeAttribute","window","addEventListener","syncAllConditionalReveals","event","handleClick","syncConditionalRevealWithInputState","$target","classList","contains","inputIsChecked","checked","toString","toggle","unCheckAllInputsExcept","allInputsWithSameName","name","$inputWithSameName","hasSameFormOwner","form","unCheckExclusiveInputs","allInputsWithSameNameAndExclusiveBehaviour","$exclusiveInput","$clickedInput","target","HTMLInputElement","type","hasAriaControls","hasBehaviourExclusive","moduleName"],"mappings":"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"}
1
+ {"version":3,"file":"checkboxes.mjs","sources":["../../../../src/govuk/components/checkboxes/checkboxes.mjs"],"sourcesContent":["import { ElementError } from '../../errors/index.mjs'\nimport { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'\n\n/**\n * Checkboxes component\n *\n * @preserve\n */\nexport class Checkboxes extends GOVUKFrontendComponent {\n /** @private */\n $inputs\n\n /**\n * Checkboxes can be associated with a 'conditionally revealed' content block\n * – for example, a checkbox for 'Phone' could reveal an additional form field\n * for the user to enter their phone number.\n *\n * These associations are made using a `data-aria-controls` attribute, which\n * is promoted to an aria-controls attribute during initialisation.\n *\n * We also need to restore the state of any conditional reveals on the page\n * (for example if the user has navigated back), and set up event handlers to\n * keep the reveal in sync with the checkbox state.\n *\n * @param {Element | null} $root - HTML element to use for checkboxes\n */\n constructor($root) {\n super($root)\n\n const $inputs = this.$root.querySelectorAll('input[type=\"checkbox\"]')\n if (!$inputs.length) {\n throw new ElementError({\n component: Checkboxes,\n identifier: 'Form inputs (`<input type=\"checkbox\">`)'\n })\n }\n\n this.$inputs = $inputs\n\n this.$inputs.forEach(($input) => {\n const targetId = $input.getAttribute('data-aria-controls')\n\n // Skip radios without data-aria-controls attributes\n if (!targetId) {\n return\n }\n\n // Throw if target conditional element does not exist.\n if (!document.getElementById(targetId)) {\n throw new ElementError({\n component: Checkboxes,\n identifier: `Conditional reveal (\\`id=\"${targetId}\"\\`)`\n })\n }\n\n // Promote the data-aria-controls attribute to a aria-controls attribute\n // so that the relationship is exposed in the AOM\n $input.setAttribute('aria-controls', targetId)\n $input.removeAttribute('data-aria-controls')\n })\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.syncAllConditionalReveals())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so sync now too.\n this.syncAllConditionalReveals()\n\n // Handle events\n this.$root.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Sync the conditional reveal states for all checkboxes in this component.\n *\n * @private\n */\n syncAllConditionalReveals() {\n this.$inputs.forEach(($input) =>\n this.syncConditionalRevealWithInputState($input)\n )\n }\n\n /**\n * Sync conditional reveal with the input state\n *\n * Synchronise the visibility of the conditional reveal, and its accessible\n * state, with the input's checked state.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n syncConditionalRevealWithInputState($input) {\n const targetId = $input.getAttribute('aria-controls')\n if (!targetId) {\n return\n }\n\n const $target = document.getElementById(targetId)\n if ($target?.classList.contains('govuk-checkboxes__conditional')) {\n const inputIsChecked = $input.checked\n\n $input.setAttribute('aria-expanded', inputIsChecked.toString())\n $target.classList.toggle(\n 'govuk-checkboxes__conditional--hidden',\n !inputIsChecked\n )\n }\n }\n\n /**\n * Uncheck other checkboxes\n *\n * Find any other checkbox inputs with the same name value, and uncheck them.\n * This is useful for when a “None of these\" checkbox is checked.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckAllInputsExcept($input) {\n const allInputsWithSameName = document.querySelectorAll(\n `input[type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameName.forEach(($inputWithSameName) => {\n const hasSameFormOwner = $input.form === $inputWithSameName.form\n if (hasSameFormOwner && $inputWithSameName !== $input) {\n $inputWithSameName.checked = false\n this.syncConditionalRevealWithInputState($inputWithSameName)\n }\n })\n }\n\n /**\n * Uncheck exclusive checkboxes\n *\n * Find any checkbox inputs with the same name value and the 'exclusive'\n * behaviour, and uncheck them. This helps prevent someone checking both a\n * regular checkbox and a \"None of these\" checkbox in the same fieldset.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckExclusiveInputs($input) {\n const allInputsWithSameNameAndExclusiveBehaviour =\n document.querySelectorAll(\n `input[data-behaviour=\"exclusive\"][type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameNameAndExclusiveBehaviour.forEach(($exclusiveInput) => {\n const hasSameFormOwner = $input.form === $exclusiveInput.form\n if (hasSameFormOwner) {\n $exclusiveInput.checked = false\n this.syncConditionalRevealWithInputState($exclusiveInput)\n }\n })\n }\n\n /**\n * Click event handler\n *\n * Handle a click within the component root – if the click occurred on a checkbox,\n * sync the state of any associated conditional reveal with the checkbox\n * state.\n *\n * @private\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $clickedInput = event.target\n\n // Ignore clicks on things that aren't checkbox inputs\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'checkbox'\n ) {\n return\n }\n\n // If the checkbox conditionally-reveals some content, sync the state\n const hasAriaControls = $clickedInput.getAttribute('aria-controls')\n if (hasAriaControls) {\n this.syncConditionalRevealWithInputState($clickedInput)\n }\n\n // No further behaviour needed for unchecking\n if (!$clickedInput.checked) {\n return\n }\n\n // Handle 'exclusive' checkbox behaviour (ie \"None of these\")\n const hasBehaviourExclusive =\n $clickedInput.getAttribute('data-behaviour') === 'exclusive'\n if (hasBehaviourExclusive) {\n this.unCheckAllInputsExcept($clickedInput)\n } else {\n this.unCheckExclusiveInputs($clickedInput)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-checkboxes'\n}\n"],"names":["Checkboxes","GOVUKFrontendComponent","constructor","$root","$inputs","querySelectorAll","length","ElementError","component","identifier","forEach","$input","targetId","getAttribute","document","getElementById","setAttribute","removeAttribute","window","addEventListener","syncAllConditionalReveals","event","handleClick","syncConditionalRevealWithInputState","$target","classList","contains","inputIsChecked","checked","toString","toggle","unCheckAllInputsExcept","allInputsWithSameName","name","$inputWithSameName","hasSameFormOwner","form","unCheckExclusiveInputs","allInputsWithSameNameAndExclusiveBehaviour","$exclusiveInput","$clickedInput","target","HTMLInputElement","type","hasAriaControls","hasBehaviourExclusive","moduleName"],"mappings":"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"}
@@ -8,9 +8,10 @@
8
8
  }
9
9
 
10
10
  .govuk-details__summary {
11
- // Make the focus outline shrink-wrap the text content of the summary
12
- display: inline-block;
11
+ display: block;
12
+ }
13
13
 
14
+ .govuk-details[open] .govuk-details__summary {
14
15
  margin-bottom: govuk-spacing(1);
15
16
  }
16
17
 
@@ -72,6 +73,10 @@
72
73
  // Absolutely position the marker against this element
73
74
  position: relative;
74
75
 
76
+ // Make the focus outline shrink-wrap the text content of the summary
77
+ width: -webkit-fit-content;
78
+ width: fit-content;
79
+
75
80
  // Allow for absolutely positioned marker and align with disclosed text
76
81
  padding-left: govuk-spacing(4) + $govuk-border-width;
77
82
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/govuk/components/details/_index.scss"],"names":[],"mappings":"AAAA;EACE;IACE,8BAA8B;IAC9B,0BAA0B;IAC1B,6CAA6C;;IAE7C,cAAc;EAChB;;EAEA;IACE,oEAAoE;IACpE,qBAAqB;;IAErB,+BAA+B;EACjC;;EAEA;IACE;MACE,aAAa;IACf;;IAEA;;MAEE,gBAAgB;IAClB;EACF;;EAEA;IACE,6BAA6B;IAC7B,gCAAgC;IAChC,8BAA8B;EAChC;;EAEA;IACE,aAAa;IACb,+BAA+B;EACjC;;EAEA;IACE,gBAAgB;EAClB;;EAEA,oDAAoD;EACpD,2EAA2E;EAC3E,iBAAiB;EACjB;IACE;MACE,gEAAgE;IAClE;;IAEA;MACE,4BAA4B;IAC9B;;IAEA;MACE,qCAAqC;MACrC,6CAA6C;MAC7C,8BAA8B;IAChC;EACF;;EAEA,2EAA2E;EAC3E,0DAA0D;EAC1D,CAAC;EACD,+DAA+D;EAC/D,CAAC;EACD,2DAA2D;EAC3D,sEAAsE;EACtE,oEAAoE;EACpE;IACE;MACE,qDAAqD;MACrD,kBAAkB;;MAElB,sEAAsE;MACtE,oDAAoD;;MAEpD,0CAA0C;MAC1C,yBAAyB;MACzB,eAAe;;MAEf;QACE,+BAA+B;MACjC;;MAEA;QACE,2BAA2B;MAC7B;IACF;IACA,+CAA+C;IAC/C;MACE,8BAA8B;IAChC;;IAEA;MACE,oCAAoC;IACtC;;IAEA,+DAA+D;IAC/D;MACE,qBAAqB;IACvB;;IAEA,4EAA4E;IAC5E,mEAAmE;IACnE;MACE,aAAa;IACf;;IAEA,4DAA4D;IAC5D;MACE,WAAW;MACX,kBAAkB;;MAElB,SAAS;MACT,SAAS;MACT,OAAO;;MAEP,YAAY;;MAEZ,0DAA0D;;MAE1D;QACE,yDAAyD;MAC3D;IACF;;IAEA;MACE,2DAA2D;IAC7D;EACF;AACF","file":"_index.scss","sourcesContent":["@include govuk-exports(\"govuk/component/details\") {\n .govuk-details {\n @include govuk-font($size: 19);\n @include govuk-text-colour;\n @include govuk-responsive-margin(6, \"bottom\");\n\n display: block;\n }\n\n .govuk-details__summary {\n // Make the focus outline shrink-wrap the text content of the summary\n display: inline-block;\n\n margin-bottom: govuk-spacing(1);\n }\n\n .govuk-details__summary-text {\n > :first-child {\n margin-top: 0;\n }\n\n > :only-child,\n > :last-child {\n margin-bottom: 0;\n }\n }\n\n .govuk-details__text {\n padding-top: govuk-spacing(3);\n padding-bottom: govuk-spacing(3);\n padding-left: govuk-spacing(4);\n }\n\n .govuk-details__text p {\n margin-top: 0;\n margin-bottom: govuk-spacing(4);\n }\n\n .govuk-details__text > :last-child {\n margin-bottom: 0;\n }\n\n // Hack to target IE8 - IE11 (and REALLY old Firefox)\n // These browsers don't support the details element, so fall back to looking\n // like inset text\n @media screen\\0 {\n .govuk-details {\n border-left: $govuk-border-width-wide solid $govuk-border-colour;\n }\n\n .govuk-details__summary {\n margin-top: govuk-spacing(3);\n }\n\n .govuk-details__summary-text {\n @include govuk-typography-weight-bold;\n @include govuk-responsive-margin(4, \"bottom\");\n padding-left: govuk-spacing(4);\n }\n }\n\n // We wrap styles for newer browsers in a feature query, which is ignored by\n // older browsers, which always expand the details element.\n //\n // Additionally, -ms-ime-align is only supported by Edge 12 - 18\n //\n // This ensures we don't use these styles in browsers which:\n // - support ES6 modules but not the <details> element (Edge 16 - 18)\n // - do not support ES6 modules or the <details> element (eg, IE8+)\n @supports not (-ms-ime-align: auto) {\n .govuk-details__summary {\n // Absolutely position the marker against this element\n position: relative;\n\n // Allow for absolutely positioned marker and align with disclosed text\n padding-left: govuk-spacing(4) + $govuk-border-width;\n\n // Style the summary to look like a link...\n color: $govuk-link-colour;\n cursor: pointer;\n\n &:hover {\n color: $govuk-link-hover-colour;\n }\n\n &:focus {\n @include govuk-focused-text;\n }\n }\n // ...but only underline the text, not the arrow\n .govuk-details__summary-text {\n @include govuk-link-decoration;\n }\n\n .govuk-details__summary:hover .govuk-details__summary-text {\n @include govuk-link-hover-decoration;\n }\n\n // Remove the underline when focussed to avoid duplicate borders\n .govuk-details__summary:focus .govuk-details__summary-text {\n text-decoration: none;\n }\n\n // Remove the default details marker so we can style our own consistently and\n // ensure it displays in Firefox (see implementation.md for details)\n .govuk-details__summary::-webkit-details-marker {\n display: none;\n }\n\n // Append our own open / closed marker using a pseudo-element\n .govuk-details__summary::before {\n content: \"\";\n position: absolute;\n\n top: -1px;\n bottom: 0;\n left: 0;\n\n margin: auto;\n\n @include govuk-shape-arrow($direction: right, $base: 14px);\n\n .govuk-details[open] > & {\n @include govuk-shape-arrow($direction: down, $base: 14px);\n }\n }\n\n .govuk-details__text {\n border-left: $govuk-border-width solid $govuk-border-colour;\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../../../src/govuk/components/details/_index.scss"],"names":[],"mappings":"AAAA;EACE;IACE,8BAA8B;IAC9B,0BAA0B;IAC1B,6CAA6C;;IAE7C,cAAc;EAChB;;EAEA;IACE,cAAc;EAChB;;EAEA;IACE,+BAA+B;EACjC;;EAEA;IACE;MACE,aAAa;IACf;;IAEA;;MAEE,gBAAgB;IAClB;EACF;;EAEA;IACE,6BAA6B;IAC7B,gCAAgC;IAChC,8BAA8B;EAChC;;EAEA;IACE,aAAa;IACb,+BAA+B;EACjC;;EAEA;IACE,gBAAgB;EAClB;;EAEA,oDAAoD;EACpD,2EAA2E;EAC3E,iBAAiB;EACjB;IACE;MACE,gEAAgE;IAClE;;IAEA;MACE,4BAA4B;IAC9B;;IAEA;MACE,qCAAqC;MACrC,6CAA6C;MAC7C,8BAA8B;IAChC;EACF;;EAEA,2EAA2E;EAC3E,0DAA0D;EAC1D,CAAC;EACD,+DAA+D;EAC/D,CAAC;EACD,2DAA2D;EAC3D,sEAAsE;EACtE,oEAAoE;EACpE;IACE;MACE,qDAAqD;MACrD,kBAAkB;;MAElB,oEAAoE;MACpE,0BAAkB;MAAlB,kBAAkB;;MAElB,sEAAsE;MACtE,oDAAoD;;MAEpD,0CAA0C;MAC1C,yBAAyB;MACzB,eAAe;;MAEf;QACE,+BAA+B;MACjC;;MAEA;QACE,2BAA2B;MAC7B;IACF;IACA,+CAA+C;IAC/C;MACE,8BAA8B;IAChC;;IAEA;MACE,oCAAoC;IACtC;;IAEA,+DAA+D;IAC/D;MACE,qBAAqB;IACvB;;IAEA,4EAA4E;IAC5E,mEAAmE;IACnE;MACE,aAAa;IACf;;IAEA,4DAA4D;IAC5D;MACE,WAAW;MACX,kBAAkB;;MAElB,SAAS;MACT,SAAS;MACT,OAAO;;MAEP,YAAY;;MAEZ,0DAA0D;;MAE1D;QACE,yDAAyD;MAC3D;IACF;;IAEA;MACE,2DAA2D;IAC7D;EACF;AACF","file":"_index.scss","sourcesContent":["@include govuk-exports(\"govuk/component/details\") {\n .govuk-details {\n @include govuk-font($size: 19);\n @include govuk-text-colour;\n @include govuk-responsive-margin(6, \"bottom\");\n\n display: block;\n }\n\n .govuk-details__summary {\n display: block;\n }\n\n .govuk-details[open] .govuk-details__summary {\n margin-bottom: govuk-spacing(1);\n }\n\n .govuk-details__summary-text {\n > :first-child {\n margin-top: 0;\n }\n\n > :only-child,\n > :last-child {\n margin-bottom: 0;\n }\n }\n\n .govuk-details__text {\n padding-top: govuk-spacing(3);\n padding-bottom: govuk-spacing(3);\n padding-left: govuk-spacing(4);\n }\n\n .govuk-details__text p {\n margin-top: 0;\n margin-bottom: govuk-spacing(4);\n }\n\n .govuk-details__text > :last-child {\n margin-bottom: 0;\n }\n\n // Hack to target IE8 - IE11 (and REALLY old Firefox)\n // These browsers don't support the details element, so fall back to looking\n // like inset text\n @media screen\\0 {\n .govuk-details {\n border-left: $govuk-border-width-wide solid $govuk-border-colour;\n }\n\n .govuk-details__summary {\n margin-top: govuk-spacing(3);\n }\n\n .govuk-details__summary-text {\n @include govuk-typography-weight-bold;\n @include govuk-responsive-margin(4, \"bottom\");\n padding-left: govuk-spacing(4);\n }\n }\n\n // We wrap styles for newer browsers in a feature query, which is ignored by\n // older browsers, which always expand the details element.\n //\n // Additionally, -ms-ime-align is only supported by Edge 12 - 18\n //\n // This ensures we don't use these styles in browsers which:\n // - support ES6 modules but not the <details> element (Edge 16 - 18)\n // - do not support ES6 modules or the <details> element (eg, IE8+)\n @supports not (-ms-ime-align: auto) {\n .govuk-details__summary {\n // Absolutely position the marker against this element\n position: relative;\n\n // Make the focus outline shrink-wrap the text content of the summary\n width: fit-content;\n\n // Allow for absolutely positioned marker and align with disclosed text\n padding-left: govuk-spacing(4) + $govuk-border-width;\n\n // Style the summary to look like a link...\n color: $govuk-link-colour;\n cursor: pointer;\n\n &:hover {\n color: $govuk-link-hover-colour;\n }\n\n &:focus {\n @include govuk-focused-text;\n }\n }\n // ...but only underline the text, not the arrow\n .govuk-details__summary-text {\n @include govuk-link-decoration;\n }\n\n .govuk-details__summary:hover .govuk-details__summary-text {\n @include govuk-link-hover-decoration;\n }\n\n // Remove the underline when focussed to avoid duplicate borders\n .govuk-details__summary:focus .govuk-details__summary-text {\n text-decoration: none;\n }\n\n // Remove the default details marker so we can style our own consistently and\n // ensure it displays in Firefox (see implementation.md for details)\n .govuk-details__summary::-webkit-details-marker {\n display: none;\n }\n\n // Append our own open / closed marker using a pseudo-element\n .govuk-details__summary::before {\n content: \"\";\n position: absolute;\n\n top: -1px;\n bottom: 0;\n left: 0;\n\n margin: auto;\n\n @include govuk-shape-arrow($direction: right, $base: 14px);\n\n .govuk-details[open] > & {\n @include govuk-shape-arrow($direction: down, $base: 14px);\n }\n }\n\n .govuk-details__text {\n border-left: $govuk-border-width solid $govuk-border-colour;\n }\n }\n}\n"]}