govuk_tech_docs 5.2.1 → 5.2.2

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +59 -0
  3. data/.npmrc +1 -0
  4. data/CHANGELOG.md +4 -0
  5. data/README.md +2 -1
  6. data/govuk_tech_docs.gemspec +1 -1
  7. data/lib/govuk_tech_docs/version.rb +1 -1
  8. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +97 -72
  9. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +97 -72
  10. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +29 -2
  11. data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
  12. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs +4 -10
  13. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +13 -11
  14. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +13 -11
  15. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +4 -4
  16. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +7 -5
  17. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +7 -5
  18. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +10 -8
  19. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +10 -8
  20. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +1 -1
  21. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +10 -5
  22. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +10 -5
  23. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +8 -12
  24. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +8 -12
  25. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs +2 -2
  26. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +9 -7
  27. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +9 -7
  28. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js +10 -8
  29. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs +10 -8
  30. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs +1 -1
  31. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js +10 -5
  32. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs +10 -5
  33. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +7 -5
  34. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +7 -5
  35. data/node_modules/govuk-frontend/dist/govuk/components/pagination/_index.scss +4 -0
  36. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +9 -7
  37. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +9 -7
  38. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +10 -5
  39. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +10 -5
  40. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/_index.scss +6 -1
  41. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +10 -5
  42. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +10 -5
  43. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/_index.scss +1 -2
  44. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +12 -19
  45. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +12 -19
  46. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs +3 -9
  47. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +12 -13
  48. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +12 -13
  49. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs +3 -3
  50. data/node_modules/govuk-frontend/dist/govuk/core/_govuk-frontend-properties.scss +1 -1
  51. data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs +5 -3
  52. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
  53. data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss +31 -2
  54. data/node_modules/govuk-frontend/dist/govuk/helpers/_visually-hidden.scss +4 -1
  55. data/node_modules/govuk-frontend/dist/govuk/i18n.mjs +4 -2
  56. data/node_modules/govuk-frontend/dist/govuk/init.mjs +52 -43
  57. data/package-lock.json +2496 -4409
  58. data/package.json +2 -2
  59. metadata +7 -5
@@ -1,11 +1,5 @@
1
- const version = '5.11.0';
1
+ const version = '5.11.2';
2
2
 
3
- function getFragmentFromUrl(url) {
4
- if (!url.includes('#')) {
5
- return undefined;
6
- }
7
- return url.split('#').pop();
8
- }
9
3
  function getBreakpoint(name) {
10
4
  const property = `--govuk-breakpoint-${name}`;
11
5
  const value = window.getComputedStyle(document.documentElement).getPropertyValue(property);
@@ -63,6 +57,9 @@ function isArray(option) {
63
57
  function isObject(option) {
64
58
  return !!option && typeof option === 'object' && !isArray(option);
65
59
  }
60
+ function isScope($scope) {
61
+ return !!$scope && ($scope instanceof Element || $scope instanceof Document);
62
+ }
66
63
  function formatErrorMessage(Component, message) {
67
64
  return `${Component.moduleName}: ${message}`;
68
65
  }
@@ -70,9 +67,6 @@ function formatErrorMessage(Component, message) {
70
67
  * @typedef ComponentWithModuleName
71
68
  * @property {string} moduleName - Name of the component
72
69
  */
73
- /**
74
- * @import { ObjectNested } from './configuration.mjs'
75
- */
76
70
 
77
71
  class GOVUKFrontendError extends Error {
78
72
  constructor(...args) {
@@ -101,7 +95,7 @@ class ConfigError extends GOVUKFrontendError {
101
95
  class ElementError extends GOVUKFrontendError {
102
96
  constructor(messageOrOptions) {
103
97
  let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
104
- if (typeof messageOrOptions === 'object') {
98
+ if (isObject(messageOrOptions)) {
105
99
  const {
106
100
  component,
107
101
  identifier,
@@ -110,7 +104,9 @@ class ElementError extends GOVUKFrontendError {
110
104
  } = messageOrOptions;
111
105
  message = identifier;
112
106
  message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';
113
- message = formatErrorMessage(component, message);
107
+ if (component) {
108
+ message = formatErrorMessage(component, message);
109
+ }
114
110
  }
115
111
  super(message);
116
112
  this.name = 'ElementError';
@@ -250,6 +246,30 @@ function normaliseDataset(Component, dataset) {
250
246
  }
251
247
  return out;
252
248
  }
249
+ function normaliseOptions(scopeOrOptions) {
250
+ let $scope = document;
251
+ let onError;
252
+ if (isObject(scopeOrOptions)) {
253
+ const options = scopeOrOptions;
254
+ if (isScope(options.scope) || options.scope === null) {
255
+ $scope = options.scope;
256
+ }
257
+ if (typeof options.onError === 'function') {
258
+ onError = options.onError;
259
+ }
260
+ }
261
+ if (isScope(scopeOrOptions)) {
262
+ $scope = scopeOrOptions;
263
+ } else if (scopeOrOptions === null) {
264
+ $scope = null;
265
+ } else if (typeof scopeOrOptions === 'function') {
266
+ onError = scopeOrOptions;
267
+ }
268
+ return {
269
+ scope: $scope,
270
+ onError
271
+ };
272
+ }
253
273
  function mergeConfigs(...configObjects) {
254
274
  const formattedConfigObject = {};
255
275
  for (const configObject of configObjects) {
@@ -344,6 +364,9 @@ function extractConfigByNamespace(schema, dataset, namespace) {
344
364
  * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
345
365
  * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
346
366
  */
367
+ /**
368
+ * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
369
+ */
347
370
 
348
371
  class I18n {
349
372
  constructor(translations = {}, config = {}) {
@@ -358,7 +381,7 @@ class I18n {
358
381
  throw new Error('i18n: lookup key missing');
359
382
  }
360
383
  let translation = this.translations[lookupKey];
361
- if (typeof (options == null ? void 0 : options.count) === 'number' && typeof translation === 'object') {
384
+ if (typeof (options == null ? void 0 : options.count) === 'number' && isObject(translation)) {
362
385
  const translationPluralForm = translation[this.getPluralSuffix(lookupKey, options.count)];
363
386
  if (translationPluralForm) {
364
387
  translation = translationPluralForm;
@@ -401,7 +424,7 @@ class I18n {
401
424
  }
402
425
  const translation = this.translations[lookupKey];
403
426
  const preferredForm = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(count) : this.selectPluralFormUsingFallbackRules(count);
404
- if (typeof translation === 'object') {
427
+ if (isObject(translation)) {
405
428
  if (preferredForm in translation) {
406
429
  return preferredForm;
407
430
  } else if ('other' in translation) {
@@ -737,11 +760,11 @@ class Accordion extends ConfigurableComponent {
737
760
  const ariaLabelParts = [];
738
761
  const $headingText = $section.querySelector(`.${this.sectionHeadingTextClass}`);
739
762
  if ($headingText) {
740
- ariaLabelParts.push(`${$headingText.textContent}`.trim());
763
+ ariaLabelParts.push($headingText.textContent.trim());
741
764
  }
742
765
  const $summary = $section.querySelector(`.${this.sectionSummaryClass}`);
743
766
  if ($summary) {
744
- ariaLabelParts.push(`${$summary.textContent}`.trim());
767
+ ariaLabelParts.push($summary.textContent.trim());
745
768
  }
746
769
  const ariaLabelMessage = expanded ? this.i18n.t('hideSectionAriaLabel') : this.i18n.t('showSectionAriaLabel');
747
770
  ariaLabelParts.push(ariaLabelMessage);
@@ -794,7 +817,7 @@ class Accordion extends ConfigurableComponent {
794
817
  if (id) {
795
818
  try {
796
819
  window.sessionStorage.setItem(id, isExpanded.toString());
797
- } catch (exception) {}
820
+ } catch (_unused) {}
798
821
  }
799
822
  }
800
823
  setInitialState($section) {
@@ -808,7 +831,7 @@ class Accordion extends ConfigurableComponent {
808
831
  if (state !== null) {
809
832
  this.setExpanded(state === 'true', $section);
810
833
  }
811
- } catch (exception) {}
834
+ } catch (_unused2) {}
812
835
  }
813
836
  }
814
837
  getButtonPunctuationEl() {
@@ -1017,7 +1040,7 @@ class CharacterCount extends ConfigurableComponent {
1017
1040
  });
1018
1041
  }
1019
1042
  this.$errorMessage = this.$root.querySelector('.govuk-error-message');
1020
- if (`${$textareaDescription.textContent}`.match(/^\s*$/)) {
1043
+ if ($textareaDescription.textContent.match(/^\s*$/)) {
1021
1044
  $textareaDescription.textContent = this.i18n.t('textareaDescription', {
1022
1045
  count: this.maxLength
1023
1046
  });
@@ -1377,7 +1400,7 @@ class ErrorSummary extends ConfigurableComponent {
1377
1400
  if (!($target instanceof HTMLAnchorElement)) {
1378
1401
  return false;
1379
1402
  }
1380
- const inputId = getFragmentFromUrl($target.href);
1403
+ const inputId = $target.hash.replace('#', '');
1381
1404
  if (!inputId) {
1382
1405
  return false;
1383
1406
  }
@@ -1690,7 +1713,6 @@ class FileUpload extends ConfigurableComponent {
1690
1713
  throw new ElementError(formatErrorMessage(FileUpload, 'File input (`<input type="file">`) attribute (`type`) is not `file`'));
1691
1714
  }
1692
1715
  this.$input = $input;
1693
- this.$input.setAttribute('hidden', 'true');
1694
1716
  if (!this.$input.id) {
1695
1717
  throw new ElementError({
1696
1718
  component: FileUpload,
@@ -1706,6 +1728,7 @@ class FileUpload extends ConfigurableComponent {
1706
1728
  $label.id = `${this.id}-label`;
1707
1729
  }
1708
1730
  this.$input.id = `${this.id}-input`;
1731
+ this.$input.setAttribute('hidden', 'true');
1709
1732
  const $button = document.createElement('button');
1710
1733
  $button.classList.add('govuk-file-upload-button');
1711
1734
  $button.type = 'button';
@@ -2358,16 +2381,10 @@ class SkipLink extends Component {
2358
2381
  super($root);
2359
2382
  const hash = this.$root.hash;
2360
2383
  const href = (_this$$root$getAttrib = this.$root.getAttribute('href')) != null ? _this$$root$getAttrib : '';
2361
- let url;
2362
- try {
2363
- url = new window.URL(this.$root.href);
2364
- } catch (error) {
2365
- throw new ElementError(`Skip link: Target link (\`href="${href}"\`) is invalid`);
2366
- }
2367
- if (url.origin !== window.location.origin || url.pathname !== window.location.pathname) {
2384
+ if (this.$root.origin !== window.location.origin || this.$root.pathname !== window.location.pathname) {
2368
2385
  return;
2369
2386
  }
2370
- const linkedElementId = getFragmentFromUrl(hash);
2387
+ const linkedElementId = hash.replace('#', '');
2371
2388
  if (!linkedElementId) {
2372
2389
  throw new ElementError(`Skip link: Target link (\`href="${href}"\`) has no hash fragment`);
2373
2390
  }
@@ -2523,7 +2540,7 @@ class Tabs extends Component {
2523
2540
  return this.$root.querySelector(`a.govuk-tabs__tab[href="${hash}"]`);
2524
2541
  }
2525
2542
  setAttributes($tab) {
2526
- const panelId = getFragmentFromUrl($tab.href);
2543
+ const panelId = $tab.hash.replace('#', '');
2527
2544
  if (!panelId) {
2528
2545
  return;
2529
2546
  }
@@ -2627,7 +2644,7 @@ class Tabs extends Component {
2627
2644
  this.createHistoryEntry($previousTab);
2628
2645
  }
2629
2646
  getPanel($tab) {
2630
- const panelId = getFragmentFromUrl($tab.href);
2647
+ const panelId = $tab.hash.replace('#', '');
2631
2648
  if (!panelId) {
2632
2649
  return null;
2633
2650
  }
@@ -2675,28 +2692,34 @@ Tabs.moduleName = 'govuk-tabs';
2675
2692
  * Use the `data-module` attributes to find, instantiate and init all of the
2676
2693
  * components provided as part of GOV.UK Frontend.
2677
2694
  *
2678
- * @param {Config & { scope?: Element, onError?: OnErrorCallback<CompatibleClass> }} [config] - Config for all components (with optional scope)
2695
+ * @param {Config | Element | Document | null} [scopeOrConfig] - Scope of the document to search within or config for all components (with optional scope)
2679
2696
  */
2680
- function initAll(config) {
2681
- var _config$scope;
2682
- config = typeof config !== 'undefined' ? config : {};
2683
- if (!isSupported()) {
2684
- if (config.onError) {
2685
- config.onError(new SupportError(), {
2697
+ function initAll(scopeOrConfig = {}) {
2698
+ const config = isObject(scopeOrConfig) ? scopeOrConfig : {};
2699
+ const options = normaliseOptions(scopeOrConfig);
2700
+ try {
2701
+ if (!isSupported()) {
2702
+ throw new SupportError();
2703
+ }
2704
+ if (options.scope === null) {
2705
+ throw new ElementError({
2706
+ element: options.scope,
2707
+ identifier: 'GOV.UK Frontend scope element (`$scope`)'
2708
+ });
2709
+ }
2710
+ } catch (error) {
2711
+ if (options.onError) {
2712
+ options.onError(error, {
2686
2713
  config
2687
2714
  });
2688
2715
  } else {
2689
- console.log(new SupportError());
2716
+ console.log(error);
2690
2717
  }
2691
2718
  return;
2692
2719
  }
2693
2720
  const components = [[Accordion, config.accordion], [Button, config.button], [CharacterCount, config.characterCount], [Checkboxes], [ErrorSummary, config.errorSummary], [ExitThisPage, config.exitThisPage], [FileUpload, config.fileUpload], [Header], [NotificationBanner, config.notificationBanner], [PasswordInput, config.passwordInput], [Radios], [ServiceNavigation], [SkipLink], [Tabs]];
2694
- const options = {
2695
- scope: (_config$scope = config.scope) != null ? _config$scope : document,
2696
- onError: config.onError
2697
- };
2698
- components.forEach(([Component, config]) => {
2699
- createAll(Component, config, options);
2721
+ components.forEach(([Component, componentConfig]) => {
2722
+ createAll(Component, componentConfig, options);
2700
2723
  });
2701
2724
  }
2702
2725
 
@@ -2712,42 +2735,42 @@ function initAll(config) {
2712
2735
  * @template {CompatibleClass} ComponentClass
2713
2736
  * @param {ComponentClass} Component - class of the component to create
2714
2737
  * @param {ComponentConfig<ComponentClass>} [config] - Config supplied to component
2715
- * @param {OnErrorCallback<ComponentClass> | Element | Document | CreateAllOptions<ComponentClass> } [createAllOptions] - options for createAll including scope of the document to search within and callback function if error throw by component on init
2738
+ * @param {OnErrorCallback<ComponentClass> | Element | Document | null | CreateAllOptions<ComponentClass>} [scopeOrOptions] - options for createAll including scope of the document to search within and callback function if error throw by component on init
2716
2739
  * @returns {Array<InstanceType<ComponentClass>>} - array of instantiated components
2717
2740
  */
2718
- function createAll(Component, config, createAllOptions) {
2719
- let $scope = document;
2720
- let onError;
2721
- if (typeof createAllOptions === 'object') {
2722
- var _createAllOptions$sco;
2723
- createAllOptions = createAllOptions;
2724
- $scope = (_createAllOptions$sco = createAllOptions.scope) != null ? _createAllOptions$sco : $scope;
2725
- onError = createAllOptions.onError;
2726
- }
2727
- if (typeof createAllOptions === 'function') {
2728
- onError = createAllOptions;
2729
- }
2730
- if (createAllOptions instanceof HTMLElement) {
2731
- $scope = createAllOptions;
2732
- }
2733
- const $elements = $scope.querySelectorAll(`[data-module="${Component.moduleName}"]`);
2734
- if (!isSupported()) {
2735
- if (onError) {
2736
- onError(new SupportError(), {
2741
+ function createAll(Component, config, scopeOrOptions) {
2742
+ let $elements;
2743
+ const options = normaliseOptions(scopeOrOptions);
2744
+ try {
2745
+ var _options$scope;
2746
+ if (!isSupported()) {
2747
+ throw new SupportError();
2748
+ }
2749
+ if (options.scope === null) {
2750
+ throw new ElementError({
2751
+ element: options.scope,
2752
+ component: Component,
2753
+ identifier: 'Scope element (`$scope`)'
2754
+ });
2755
+ }
2756
+ $elements = (_options$scope = options.scope) == null ? void 0 : _options$scope.querySelectorAll(`[data-module="${Component.moduleName}"]`);
2757
+ } catch (error) {
2758
+ if (options.onError) {
2759
+ options.onError(error, {
2737
2760
  component: Component,
2738
2761
  config
2739
2762
  });
2740
2763
  } else {
2741
- console.log(new SupportError());
2764
+ console.log(error);
2742
2765
  }
2743
2766
  return [];
2744
2767
  }
2745
- return Array.from($elements).map($element => {
2768
+ return Array.from($elements != null ? $elements : []).map($element => {
2746
2769
  try {
2747
2770
  return typeof config !== 'undefined' ? new Component($element, config) : new Component($element);
2748
2771
  } catch (error) {
2749
- if (onError) {
2750
- onError(error, {
2772
+ if (options.onError) {
2773
+ options.onError(error, {
2751
2774
  element: $element,
2752
2775
  component: Component,
2753
2776
  config
@@ -2766,6 +2789,8 @@ function createAll(Component, config, createAllOptions) {
2766
2789
  * Config for all components via `initAll()`
2767
2790
  *
2768
2791
  * @typedef {object} Config
2792
+ * @property {Element | Document | null} [scope] - Scope of the document to search within
2793
+ * @property {OnErrorCallback<CompatibleClass>} [onError] - Initialisation error callback
2769
2794
  * @property {AccordionConfig} [accordion] - Accordion config
2770
2795
  * @property {ButtonConfig} [button] - Button config
2771
2796
  * @property {CharacterCountConfig} [characterCount] - Character Count config
@@ -2790,7 +2815,7 @@ function createAll(Component, config, createAllOptions) {
2790
2815
  /**
2791
2816
  * Component config keys, e.g. `accordion` and `characterCount`
2792
2817
  *
2793
- * @typedef {keyof Config} ConfigKey
2818
+ * @typedef {keyof Omit<Config, 'scope' | 'onError'>} ConfigKey
2794
2819
  */
2795
2820
  /**
2796
2821
  * @template {CompatibleClass} ComponentClass
@@ -2801,7 +2826,7 @@ function createAll(Component, config, createAllOptions) {
2801
2826
  * @typedef {object} ErrorContext
2802
2827
  * @property {Element} [element] - Element used for component module initialisation
2803
2828
  * @property {ComponentClass} [component] - Class of component
2804
- * @property {ComponentConfig<ComponentClass>} config - Config supplied to component
2829
+ * @property {Config | ComponentConfig<ComponentClass>} [config] - Config supplied to components
2805
2830
  */
2806
2831
  /**
2807
2832
  * @template {CompatibleClass} ComponentClass
@@ -2812,7 +2837,7 @@ function createAll(Component, config, createAllOptions) {
2812
2837
  /**
2813
2838
  * @template {CompatibleClass} ComponentClass
2814
2839
  * @typedef {object} CreateAllOptions
2815
- * @property {Element | Document} [scope] - scope of the document to search within
2840
+ * @property {Element | Document | null} [scope] - scope of the document to search within
2816
2841
  * @property {OnErrorCallback<ComponentClass>} [onError] - callback function if error throw by component on init
2817
2842
  */
2818
2843
 
@@ -1,6 +1,6 @@
1
1
  import { Component } from '../component.mjs';
2
2
  import { ConfigError } from '../errors/index.mjs';
3
- import { isObject, formatErrorMessage } from './index.mjs';
3
+ import { isObject, formatErrorMessage, isScope } from './index.mjs';
4
4
 
5
5
  const configOverride = Symbol.for('configOverride');
6
6
  class ConfigurableComponent extends Component {
@@ -70,6 +70,30 @@ function normaliseDataset(Component, dataset) {
70
70
  }
71
71
  return out;
72
72
  }
73
+ function normaliseOptions(scopeOrOptions) {
74
+ let $scope = document;
75
+ let onError;
76
+ if (isObject(scopeOrOptions)) {
77
+ const options = scopeOrOptions;
78
+ if (isScope(options.scope) || options.scope === null) {
79
+ $scope = options.scope;
80
+ }
81
+ if (typeof options.onError === 'function') {
82
+ onError = options.onError;
83
+ }
84
+ }
85
+ if (isScope(scopeOrOptions)) {
86
+ $scope = scopeOrOptions;
87
+ } else if (scopeOrOptions === null) {
88
+ $scope = null;
89
+ } else if (typeof scopeOrOptions === 'function') {
90
+ onError = scopeOrOptions;
91
+ }
92
+ return {
93
+ scope: $scope,
94
+ onError
95
+ };
96
+ }
73
97
  function mergeConfigs(...configObjects) {
74
98
  const formattedConfigObject = {};
75
99
  for (const configObject of configObjects) {
@@ -164,6 +188,9 @@ function extractConfigByNamespace(schema, dataset, namespace) {
164
188
  * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
165
189
  * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
166
190
  */
191
+ /**
192
+ * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
193
+ */
167
194
 
168
- export { ConfigurableComponent, configOverride, extractConfigByNamespace, mergeConfigs, normaliseDataset, normaliseString, validateConfig };
195
+ export { ConfigurableComponent, configOverride, extractConfigByNamespace, mergeConfigs, normaliseDataset, normaliseOptions, normaliseString, validateConfig };
169
196
  //# sourceMappingURL=configuration.mjs.map
@@ -1,4 +1,4 @@
1
- const version = '5.11.0';
1
+ const version = '5.11.2';
2
2
 
3
3
  export { version };
4
4
  //# sourceMappingURL=govuk-frontend-version.mjs.map
@@ -1,9 +1,3 @@
1
- function getFragmentFromUrl(url) {
2
- if (!url.includes('#')) {
3
- return undefined;
4
- }
5
- return url.split('#').pop();
6
- }
7
1
  function getBreakpoint(name) {
8
2
  const property = `--govuk-breakpoint-${name}`;
9
3
  const value = window.getComputedStyle(document.documentElement).getPropertyValue(property);
@@ -61,6 +55,9 @@ function isArray(option) {
61
55
  function isObject(option) {
62
56
  return !!option && typeof option === 'object' && !isArray(option);
63
57
  }
58
+ function isScope($scope) {
59
+ return !!$scope && ($scope instanceof Element || $scope instanceof Document);
60
+ }
64
61
  function formatErrorMessage(Component, message) {
65
62
  return `${Component.moduleName}: ${message}`;
66
63
  }
@@ -68,9 +65,6 @@ function formatErrorMessage(Component, message) {
68
65
  * @typedef ComponentWithModuleName
69
66
  * @property {string} moduleName - Name of the component
70
67
  */
71
- /**
72
- * @import { ObjectNested } from './configuration.mjs'
73
- */
74
68
 
75
- export { formatErrorMessage, getBreakpoint, getFragmentFromUrl, isInitialised, isObject, isSupported, setFocus };
69
+ export { formatErrorMessage, getBreakpoint, isInitialised, isObject, isScope, isSupported, setFocus };
76
70
  //# sourceMappingURL=index.mjs.map
@@ -36,9 +36,6 @@
36
36
  * @typedef ComponentWithModuleName
37
37
  * @property {string} moduleName - Name of the component
38
38
  */
39
- /**
40
- * @import { ObjectNested } from './configuration.mjs'
41
- */
42
39
 
43
40
  class GOVUKFrontendError extends Error {
44
41
  constructor(...args) {
@@ -67,7 +64,7 @@
67
64
  class ElementError extends GOVUKFrontendError {
68
65
  constructor(messageOrOptions) {
69
66
  let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
70
- if (typeof messageOrOptions === 'object') {
67
+ if (isObject(messageOrOptions)) {
71
68
  const {
72
69
  component,
73
70
  identifier,
@@ -76,7 +73,9 @@
76
73
  } = messageOrOptions;
77
74
  message = identifier;
78
75
  message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';
79
- message = formatErrorMessage(component, message);
76
+ if (component) {
77
+ message = formatErrorMessage(component, message);
78
+ }
80
79
  }
81
80
  super(message);
82
81
  this.name = 'ElementError';
@@ -290,6 +289,9 @@
290
289
  * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
291
290
  * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
292
291
  */
292
+ /**
293
+ * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
294
+ */
293
295
 
294
296
  class I18n {
295
297
  constructor(translations = {}, config = {}) {
@@ -304,7 +306,7 @@
304
306
  throw new Error('i18n: lookup key missing');
305
307
  }
306
308
  let translation = this.translations[lookupKey];
307
- if (typeof (options == null ? void 0 : options.count) === 'number' && typeof translation === 'object') {
309
+ if (typeof (options == null ? void 0 : options.count) === 'number' && isObject(translation)) {
308
310
  const translationPluralForm = translation[this.getPluralSuffix(lookupKey, options.count)];
309
311
  if (translationPluralForm) {
310
312
  translation = translationPluralForm;
@@ -347,7 +349,7 @@
347
349
  }
348
350
  const translation = this.translations[lookupKey];
349
351
  const preferredForm = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(count) : this.selectPluralFormUsingFallbackRules(count);
350
- if (typeof translation === 'object') {
352
+ if (isObject(translation)) {
351
353
  if (preferredForm in translation) {
352
354
  return preferredForm;
353
355
  } else if ('other' in translation) {
@@ -683,11 +685,11 @@
683
685
  const ariaLabelParts = [];
684
686
  const $headingText = $section.querySelector(`.${this.sectionHeadingTextClass}`);
685
687
  if ($headingText) {
686
- ariaLabelParts.push(`${$headingText.textContent}`.trim());
688
+ ariaLabelParts.push($headingText.textContent.trim());
687
689
  }
688
690
  const $summary = $section.querySelector(`.${this.sectionSummaryClass}`);
689
691
  if ($summary) {
690
- ariaLabelParts.push(`${$summary.textContent}`.trim());
692
+ ariaLabelParts.push($summary.textContent.trim());
691
693
  }
692
694
  const ariaLabelMessage = expanded ? this.i18n.t('hideSectionAriaLabel') : this.i18n.t('showSectionAriaLabel');
693
695
  ariaLabelParts.push(ariaLabelMessage);
@@ -740,7 +742,7 @@
740
742
  if (id) {
741
743
  try {
742
744
  window.sessionStorage.setItem(id, isExpanded.toString());
743
- } catch (exception) {}
745
+ } catch (_unused) {}
744
746
  }
745
747
  }
746
748
  setInitialState($section) {
@@ -754,7 +756,7 @@
754
756
  if (state !== null) {
755
757
  this.setExpanded(state === 'true', $section);
756
758
  }
757
- } catch (exception) {}
759
+ } catch (_unused2) {}
758
760
  }
759
761
  }
760
762
  getButtonPunctuationEl() {
@@ -30,9 +30,6 @@ function formatErrorMessage(Component, message) {
30
30
  * @typedef ComponentWithModuleName
31
31
  * @property {string} moduleName - Name of the component
32
32
  */
33
- /**
34
- * @import { ObjectNested } from './configuration.mjs'
35
- */
36
33
 
37
34
  class GOVUKFrontendError extends Error {
38
35
  constructor(...args) {
@@ -61,7 +58,7 @@ class ConfigError extends GOVUKFrontendError {
61
58
  class ElementError extends GOVUKFrontendError {
62
59
  constructor(messageOrOptions) {
63
60
  let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
64
- if (typeof messageOrOptions === 'object') {
61
+ if (isObject(messageOrOptions)) {
65
62
  const {
66
63
  component,
67
64
  identifier,
@@ -70,7 +67,9 @@ class ElementError extends GOVUKFrontendError {
70
67
  } = messageOrOptions;
71
68
  message = identifier;
72
69
  message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';
73
- message = formatErrorMessage(component, message);
70
+ if (component) {
71
+ message = formatErrorMessage(component, message);
72
+ }
74
73
  }
75
74
  super(message);
76
75
  this.name = 'ElementError';
@@ -284,6 +283,9 @@ function extractConfigByNamespace(schema, dataset, namespace) {
284
283
  * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
285
284
  * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
286
285
  */
286
+ /**
287
+ * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
288
+ */
287
289
 
288
290
  class I18n {
289
291
  constructor(translations = {}, config = {}) {
@@ -298,7 +300,7 @@ class I18n {
298
300
  throw new Error('i18n: lookup key missing');
299
301
  }
300
302
  let translation = this.translations[lookupKey];
301
- if (typeof (options == null ? void 0 : options.count) === 'number' && typeof translation === 'object') {
303
+ if (typeof (options == null ? void 0 : options.count) === 'number' && isObject(translation)) {
302
304
  const translationPluralForm = translation[this.getPluralSuffix(lookupKey, options.count)];
303
305
  if (translationPluralForm) {
304
306
  translation = translationPluralForm;
@@ -341,7 +343,7 @@ class I18n {
341
343
  }
342
344
  const translation = this.translations[lookupKey];
343
345
  const preferredForm = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(count) : this.selectPluralFormUsingFallbackRules(count);
344
- if (typeof translation === 'object') {
346
+ if (isObject(translation)) {
345
347
  if (preferredForm in translation) {
346
348
  return preferredForm;
347
349
  } else if ('other' in translation) {
@@ -677,11 +679,11 @@ class Accordion extends ConfigurableComponent {
677
679
  const ariaLabelParts = [];
678
680
  const $headingText = $section.querySelector(`.${this.sectionHeadingTextClass}`);
679
681
  if ($headingText) {
680
- ariaLabelParts.push(`${$headingText.textContent}`.trim());
682
+ ariaLabelParts.push($headingText.textContent.trim());
681
683
  }
682
684
  const $summary = $section.querySelector(`.${this.sectionSummaryClass}`);
683
685
  if ($summary) {
684
- ariaLabelParts.push(`${$summary.textContent}`.trim());
686
+ ariaLabelParts.push($summary.textContent.trim());
685
687
  }
686
688
  const ariaLabelMessage = expanded ? this.i18n.t('hideSectionAriaLabel') : this.i18n.t('showSectionAriaLabel');
687
689
  ariaLabelParts.push(ariaLabelMessage);
@@ -734,7 +736,7 @@ class Accordion extends ConfigurableComponent {
734
736
  if (id) {
735
737
  try {
736
738
  window.sessionStorage.setItem(id, isExpanded.toString());
737
- } catch (exception) {}
739
+ } catch (_unused) {}
738
740
  }
739
741
  }
740
742
  setInitialState($section) {
@@ -748,7 +750,7 @@ class Accordion extends ConfigurableComponent {
748
750
  if (state !== null) {
749
751
  this.setExpanded(state === 'true', $section);
750
752
  }
751
- } catch (exception) {}
753
+ } catch (_unused2) {}
752
754
  }
753
755
  }
754
756
  getButtonPunctuationEl() {
@@ -201,11 +201,11 @@ class Accordion extends ConfigurableComponent {
201
201
  const ariaLabelParts = [];
202
202
  const $headingText = $section.querySelector(`.${this.sectionHeadingTextClass}`);
203
203
  if ($headingText) {
204
- ariaLabelParts.push(`${$headingText.textContent}`.trim());
204
+ ariaLabelParts.push($headingText.textContent.trim());
205
205
  }
206
206
  const $summary = $section.querySelector(`.${this.sectionSummaryClass}`);
207
207
  if ($summary) {
208
- ariaLabelParts.push(`${$summary.textContent}`.trim());
208
+ ariaLabelParts.push($summary.textContent.trim());
209
209
  }
210
210
  const ariaLabelMessage = expanded ? this.i18n.t('hideSectionAriaLabel') : this.i18n.t('showSectionAriaLabel');
211
211
  ariaLabelParts.push(ariaLabelMessage);
@@ -258,7 +258,7 @@ class Accordion extends ConfigurableComponent {
258
258
  if (id) {
259
259
  try {
260
260
  window.sessionStorage.setItem(id, isExpanded.toString());
261
- } catch (exception) {}
261
+ } catch (_unused) {}
262
262
  }
263
263
  }
264
264
  setInitialState($section) {
@@ -272,7 +272,7 @@ class Accordion extends ConfigurableComponent {
272
272
  if (state !== null) {
273
273
  this.setExpanded(state === 'true', $section);
274
274
  }
275
- } catch (exception) {}
275
+ } catch (_unused2) {}
276
276
  }
277
277
  }
278
278
  getButtonPunctuationEl() {