@ministryofjustice/frontend 5.0.0 → 5.1.1

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 (114) hide show
  1. package/moj/all.bundle.js +1598 -1062
  2. package/moj/all.bundle.js.map +1 -1
  3. package/moj/all.bundle.mjs +1894 -1054
  4. package/moj/all.bundle.mjs.map +1 -1
  5. package/moj/all.mjs +7 -90
  6. package/moj/all.mjs.map +1 -1
  7. package/moj/all.scss +1 -0
  8. package/moj/all.scss.map +1 -1
  9. package/moj/common/index.mjs +57 -0
  10. package/moj/common/index.mjs.map +1 -0
  11. package/moj/common/moj-frontend-version.mjs +14 -0
  12. package/moj/common/moj-frontend-version.mjs.map +1 -0
  13. package/moj/components/add-another/add-another.bundle.js +105 -76
  14. package/moj/components/add-another/add-another.bundle.js.map +1 -1
  15. package/moj/components/add-another/add-another.bundle.mjs +222 -71
  16. package/moj/components/add-another/add-another.bundle.mjs.map +1 -1
  17. package/moj/components/add-another/add-another.mjs +103 -72
  18. package/moj/components/add-another/add-another.mjs.map +1 -1
  19. package/moj/components/alert/alert.bundle.js +115 -191
  20. package/moj/components/alert/alert.bundle.js.map +1 -1
  21. package/moj/components/alert/alert.bundle.mjs +354 -186
  22. package/moj/components/alert/alert.bundle.mjs.map +1 -1
  23. package/moj/components/alert/alert.mjs +55 -140
  24. package/moj/components/alert/alert.mjs.map +1 -1
  25. package/moj/components/button-menu/README.md +3 -1
  26. package/moj/components/button-menu/button-menu.bundle.js +91 -120
  27. package/moj/components/button-menu/button-menu.bundle.js.map +1 -1
  28. package/moj/components/button-menu/button-menu.bundle.mjs +329 -114
  29. package/moj/components/button-menu/button-menu.bundle.mjs.map +1 -1
  30. package/moj/components/button-menu/button-menu.mjs +89 -116
  31. package/moj/components/button-menu/button-menu.mjs.map +1 -1
  32. package/moj/components/date-picker/date-picker.bundle.js +174 -154
  33. package/moj/components/date-picker/date-picker.bundle.js.map +1 -1
  34. package/moj/components/date-picker/date-picker.bundle.mjs +411 -147
  35. package/moj/components/date-picker/date-picker.bundle.mjs.map +1 -1
  36. package/moj/components/date-picker/date-picker.mjs +172 -150
  37. package/moj/components/date-picker/date-picker.mjs.map +1 -1
  38. package/moj/components/filter/template.njk +1 -1
  39. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js +133 -44
  40. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js.map +1 -1
  41. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs +374 -41
  42. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs.map +1 -1
  43. package/moj/components/filter-toggle-button/filter-toggle-button.mjs +131 -40
  44. package/moj/components/filter-toggle-button/filter-toggle-button.mjs.map +1 -1
  45. package/moj/components/form-validator/form-validator.bundle.js +159 -69
  46. package/moj/components/form-validator/form-validator.bundle.js.map +1 -1
  47. package/moj/components/form-validator/form-validator.bundle.mjs +399 -65
  48. package/moj/components/form-validator/form-validator.bundle.mjs.map +1 -1
  49. package/moj/components/form-validator/form-validator.mjs +134 -54
  50. package/moj/components/form-validator/form-validator.mjs.map +1 -1
  51. package/moj/components/multi-file-upload/multi-file-upload.bundle.js +291 -117
  52. package/moj/components/multi-file-upload/multi-file-upload.bundle.js.map +1 -1
  53. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs +527 -109
  54. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs.map +1 -1
  55. package/moj/components/multi-file-upload/multi-file-upload.mjs +288 -101
  56. package/moj/components/multi-file-upload/multi-file-upload.mjs.map +1 -1
  57. package/moj/components/multi-file-upload/template.njk +1 -1
  58. package/moj/components/multi-select/multi-select.bundle.js +106 -41
  59. package/moj/components/multi-select/multi-select.bundle.js.map +1 -1
  60. package/moj/components/multi-select/multi-select.bundle.mjs +346 -37
  61. package/moj/components/multi-select/multi-select.bundle.mjs.map +1 -1
  62. package/moj/components/multi-select/multi-select.mjs +104 -37
  63. package/moj/components/multi-select/multi-select.mjs.map +1 -1
  64. package/moj/components/password-reveal/_password-reveal.scss +3 -1
  65. package/moj/components/password-reveal/_password-reveal.scss.map +1 -1
  66. package/moj/components/password-reveal/password-reveal.bundle.js +32 -29
  67. package/moj/components/password-reveal/password-reveal.bundle.js.map +1 -1
  68. package/moj/components/password-reveal/password-reveal.bundle.mjs +149 -24
  69. package/moj/components/password-reveal/password-reveal.bundle.mjs.map +1 -1
  70. package/moj/components/password-reveal/password-reveal.mjs +30 -25
  71. package/moj/components/password-reveal/password-reveal.mjs.map +1 -1
  72. package/moj/components/rich-text-editor/README.md +4 -3
  73. package/moj/components/rich-text-editor/rich-text-editor.bundle.js +127 -62
  74. package/moj/components/rich-text-editor/rich-text-editor.bundle.js.map +1 -1
  75. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs +367 -58
  76. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs.map +1 -1
  77. package/moj/components/rich-text-editor/rich-text-editor.mjs +125 -58
  78. package/moj/components/rich-text-editor/rich-text-editor.mjs.map +1 -1
  79. package/moj/components/search-toggle/search-toggle.bundle.js +94 -26
  80. package/moj/components/search-toggle/search-toggle.bundle.js.map +1 -1
  81. package/moj/components/search-toggle/search-toggle.bundle.mjs +334 -22
  82. package/moj/components/search-toggle/search-toggle.bundle.mjs.map +1 -1
  83. package/moj/components/search-toggle/search-toggle.mjs +92 -22
  84. package/moj/components/search-toggle/search-toggle.mjs.map +1 -1
  85. package/moj/components/sortable-table/_sortable-table.scss +3 -42
  86. package/moj/components/sortable-table/_sortable-table.scss.map +1 -1
  87. package/moj/components/sortable-table/sortable-table.bundle.js +200 -83
  88. package/moj/components/sortable-table/sortable-table.bundle.js.map +1 -1
  89. package/moj/components/sortable-table/sortable-table.bundle.mjs +439 -78
  90. package/moj/components/sortable-table/sortable-table.bundle.mjs.map +1 -1
  91. package/moj/components/sortable-table/sortable-table.mjs +198 -79
  92. package/moj/components/sortable-table/sortable-table.mjs.map +1 -1
  93. package/moj/core/_all.scss +3 -0
  94. package/moj/core/_all.scss.map +1 -0
  95. package/moj/core/_moj-frontend-properties.scss +7 -0
  96. package/moj/core/_moj-frontend-properties.scss.map +1 -0
  97. package/moj/filters/prototype-kit-13-filters.js +4 -3
  98. package/moj/helpers.bundle.js +22 -77
  99. package/moj/helpers.bundle.js.map +1 -1
  100. package/moj/helpers.bundle.mjs +23 -74
  101. package/moj/helpers.bundle.mjs.map +1 -1
  102. package/moj/helpers.mjs +23 -74
  103. package/moj/helpers.mjs.map +1 -1
  104. package/moj/moj-frontend.min.css +1 -1
  105. package/moj/moj-frontend.min.css.map +1 -1
  106. package/moj/moj-frontend.min.js +1 -1
  107. package/moj/moj-frontend.min.js.map +1 -1
  108. package/package.json +1 -1
  109. package/moj/version.bundle.js +0 -12
  110. package/moj/version.bundle.js.map +0 -1
  111. package/moj/version.bundle.mjs +0 -4
  112. package/moj/version.bundle.mjs.map +0 -1
  113. package/moj/version.mjs +0 -4
  114. package/moj/version.mjs.map +0 -1
@@ -1,46 +1,116 @@
1
- class SearchToggle {
2
- constructor(options) {
3
- this.options = options;
4
- this.container = this.options.search.container;
5
- this.toggleButtonContainer = this.options.toggleButton.container;
6
- if (this.container.hasAttribute('data-moj-search-toggle-init')) {
1
+ import { ConfigurableComponent } from 'govuk-frontend';
2
+
3
+ /**
4
+ * @augments {ConfigurableComponent<SearchToggleConfig>}
5
+ */
6
+ class SearchToggle extends ConfigurableComponent {
7
+ /**
8
+ * @param {Element | null} $root - HTML element to use for search toggle
9
+ * @param {SearchToggleConfig} [config] - Search toggle config
10
+ */
11
+ constructor($root, config = {}) {
12
+ var _this$config$searchCo, _this$config$toggleBu;
13
+ super($root, config);
14
+ const $searchContainer = (_this$config$searchCo = this.config.searchContainer.element) != null ? _this$config$searchCo : this.$root.querySelector(this.config.searchContainer.selector);
15
+ const $toggleButtonContainer = (_this$config$toggleBu = this.config.toggleButtonContainer.element) != null ? _this$config$toggleBu : this.$root.querySelector(this.config.toggleButtonContainer.selector);
16
+ if (!$searchContainer || !$toggleButtonContainer || !($searchContainer instanceof HTMLElement) || !($toggleButtonContainer instanceof HTMLElement)) {
7
17
  return this;
8
18
  }
9
- this.container.setAttribute('data-moj-search-toggle-init', '');
19
+ this.$searchContainer = $searchContainer;
20
+ this.$toggleButtonContainer = $toggleButtonContainer;
10
21
  const svg = '<svg viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="moj-search-toggle__button__icon"><path d="M7.433,12.5790048 C6.06762625,12.5808611 4.75763941,12.0392925 3.79217348,11.0738265 C2.82670755,10.1083606 2.28513891,8.79837375 2.28699522,7.433 C2.28513891,6.06762625 2.82670755,4.75763941 3.79217348,3.79217348 C4.75763941,2.82670755 6.06762625,2.28513891 7.433,2.28699522 C8.79837375,2.28513891 10.1083606,2.82670755 11.0738265,3.79217348 C12.0392925,4.75763941 12.5808611,6.06762625 12.5790048,7.433 C12.5808611,8.79837375 12.0392925,10.1083606 11.0738265,11.0738265 C10.1083606,12.0392925 8.79837375,12.5808611 7.433,12.5790048 L7.433,12.5790048 Z M14.293,12.579 L13.391,12.579 L13.071,12.269 C14.2300759,10.9245158 14.8671539,9.20813198 14.866,7.433 C14.866,3.32786745 11.5381325,-1.65045755e-15 7.433,-1.65045755e-15 C3.32786745,-1.65045755e-15 -1.65045755e-15,3.32786745 -1.65045755e-15,7.433 C-1.65045755e-15,11.5381325 3.32786745,14.866 7.433,14.866 C9.208604,14.8671159 10.9253982,14.2296624 12.27,13.07 L12.579,13.39 L12.579,14.294 L18.296,20 L20,18.296 L14.294,12.579 L14.293,12.579 Z"></path></svg>';
11
- this.toggleButton = document.createElement('button');
12
- this.toggleButton.setAttribute('class', 'moj-search-toggle__button');
13
- this.toggleButton.setAttribute('type', 'button');
14
- this.toggleButton.setAttribute('aria-haspopup', 'true');
15
- this.toggleButton.setAttribute('aria-expanded', 'false');
16
- this.toggleButton.innerHTML = `${this.options.toggleButton.text} ${svg}`;
17
- this.toggleButton.addEventListener('click', this.onToggleButtonClick.bind(this));
18
- this.toggleButtonContainer.append(this.toggleButton);
22
+ this.$toggleButton = document.createElement('button');
23
+ this.$toggleButton.setAttribute('class', 'moj-search-toggle__button');
24
+ this.$toggleButton.setAttribute('type', 'button');
25
+ this.$toggleButton.setAttribute('aria-haspopup', 'true');
26
+ this.$toggleButton.setAttribute('aria-expanded', 'false');
27
+ this.$toggleButton.innerHTML = `${this.config.toggleButton.text} ${svg}`;
28
+ this.$toggleButton.addEventListener('click', this.onToggleButtonClick.bind(this));
29
+ this.$toggleButtonContainer.append(this.$toggleButton);
19
30
  document.addEventListener('click', this.onDocumentClick.bind(this));
20
31
  document.addEventListener('focusin', this.onDocumentClick.bind(this));
21
32
  }
22
33
  showMenu() {
23
- this.toggleButton.setAttribute('aria-expanded', 'true');
24
- this.container.classList.remove('moj-js-hidden');
25
- this.container.querySelector('input').focus();
34
+ this.$toggleButton.setAttribute('aria-expanded', 'true');
35
+ this.$searchContainer.classList.remove('moj-js-hidden');
36
+ this.$searchContainer.querySelector('input').focus();
26
37
  }
27
38
  hideMenu() {
28
- this.container.classList.add('moj-js-hidden');
29
- this.toggleButton.setAttribute('aria-expanded', 'false');
39
+ this.$searchContainer.classList.add('moj-js-hidden');
40
+ this.$toggleButton.setAttribute('aria-expanded', 'false');
30
41
  }
31
42
  onToggleButtonClick() {
32
- if (this.toggleButton.getAttribute('aria-expanded') === 'false') {
43
+ if (this.$toggleButton.getAttribute('aria-expanded') === 'false') {
33
44
  this.showMenu();
34
45
  } else {
35
46
  this.hideMenu();
36
47
  }
37
48
  }
49
+
50
+ /**
51
+ * @param {MouseEvent | FocusEvent} event
52
+ */
38
53
  onDocumentClick(event) {
39
- if (!this.toggleButtonContainer.contains(event.target) && !this.container.contains(event.target)) {
54
+ if (event.target instanceof Node && !this.$toggleButtonContainer.contains(event.target) && !this.$searchContainer.contains(event.target)) {
40
55
  this.hideMenu();
41
56
  }
42
57
  }
58
+
59
+ /**
60
+ * Name for the component used when initialising using data-module attributes.
61
+ */
43
62
  }
44
63
 
64
+ /**
65
+ * @typedef {object} SearchToggleConfig
66
+ * @property {object} [searchContainer] - Search config
67
+ * @property {string} [searchContainer.selector] - Selector for search container
68
+ * @property {Element | null} [searchContainer.element] - HTML element for search container
69
+ * @property {object} [toggleButton] - Toggle button config
70
+ * @property {string} [toggleButton.text] - Text for toggle button
71
+ * @property {object} [toggleButtonContainer] - Toggle button container config
72
+ * @property {string} [toggleButtonContainer.selector] - Selector for toggle button container
73
+ * @property {Element | null} [toggleButtonContainer.element] - HTML element for toggle button container
74
+ */
75
+
76
+ /**
77
+ * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
78
+ */
79
+ SearchToggle.moduleName = 'moj-search-toggle';
80
+ /**
81
+ * Search toggle config
82
+ *
83
+ * @type {SearchToggleConfig}
84
+ */
85
+ SearchToggle.defaults = Object.freeze({
86
+ searchContainer: {
87
+ selector: '.moj-search'
88
+ },
89
+ toggleButton: {
90
+ text: 'Search'
91
+ },
92
+ toggleButtonContainer: {
93
+ selector: '.moj-search-toggle__toggle'
94
+ }
95
+ });
96
+ /**
97
+ * Search toggle config schema
98
+ *
99
+ * @satisfies {Schema<SearchToggleConfig>}
100
+ */
101
+ SearchToggle.schema = Object.freeze(/** @type {const} */{
102
+ properties: {
103
+ searchContainer: {
104
+ type: 'object'
105
+ },
106
+ toggleButton: {
107
+ type: 'object'
108
+ },
109
+ toggleButtonContainer: {
110
+ type: 'object'
111
+ }
112
+ }
113
+ });
114
+
45
115
  export { SearchToggle };
46
116
  //# sourceMappingURL=search-toggle.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"search-toggle.mjs","sources":["../../../../src/moj/components/search-toggle/search-toggle.mjs"],"sourcesContent":["export class SearchToggle {\n constructor(options) {\n this.options = options\n this.container = this.options.search.container\n this.toggleButtonContainer = this.options.toggleButton.container\n\n if (this.container.hasAttribute('data-moj-search-toggle-init')) {\n return this\n }\n\n this.container.setAttribute('data-moj-search-toggle-init', '')\n\n const svg =\n '<svg viewBox=\"0 0 20 20\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" class=\"moj-search-toggle__button__icon\"><path d=\"M7.433,12.5790048 C6.06762625,12.5808611 4.75763941,12.0392925 3.79217348,11.0738265 C2.82670755,10.1083606 2.28513891,8.79837375 2.28699522,7.433 C2.28513891,6.06762625 2.82670755,4.75763941 3.79217348,3.79217348 C4.75763941,2.82670755 6.06762625,2.28513891 7.433,2.28699522 C8.79837375,2.28513891 10.1083606,2.82670755 11.0738265,3.79217348 C12.0392925,4.75763941 12.5808611,6.06762625 12.5790048,7.433 C12.5808611,8.79837375 12.0392925,10.1083606 11.0738265,11.0738265 C10.1083606,12.0392925 8.79837375,12.5808611 7.433,12.5790048 L7.433,12.5790048 Z M14.293,12.579 L13.391,12.579 L13.071,12.269 C14.2300759,10.9245158 14.8671539,9.20813198 14.866,7.433 C14.866,3.32786745 11.5381325,-1.65045755e-15 7.433,-1.65045755e-15 C3.32786745,-1.65045755e-15 -1.65045755e-15,3.32786745 -1.65045755e-15,7.433 C-1.65045755e-15,11.5381325 3.32786745,14.866 7.433,14.866 C9.208604,14.8671159 10.9253982,14.2296624 12.27,13.07 L12.579,13.39 L12.579,14.294 L18.296,20 L20,18.296 L14.294,12.579 L14.293,12.579 Z\"></path></svg>'\n\n this.toggleButton = document.createElement('button')\n this.toggleButton.setAttribute('class', 'moj-search-toggle__button')\n this.toggleButton.setAttribute('type', 'button')\n this.toggleButton.setAttribute('aria-haspopup', 'true')\n this.toggleButton.setAttribute('aria-expanded', 'false')\n this.toggleButton.innerHTML = `${this.options.toggleButton.text} ${svg}`\n\n this.toggleButton.addEventListener(\n 'click',\n this.onToggleButtonClick.bind(this)\n )\n\n this.toggleButtonContainer.append(this.toggleButton)\n\n document.addEventListener('click', this.onDocumentClick.bind(this))\n document.addEventListener('focusin', this.onDocumentClick.bind(this))\n }\n\n showMenu() {\n this.toggleButton.setAttribute('aria-expanded', 'true')\n this.container.classList.remove('moj-js-hidden')\n this.container.querySelector('input').focus()\n }\n\n hideMenu() {\n this.container.classList.add('moj-js-hidden')\n this.toggleButton.setAttribute('aria-expanded', 'false')\n }\n\n onToggleButtonClick() {\n if (this.toggleButton.getAttribute('aria-expanded') === 'false') {\n this.showMenu()\n } else {\n this.hideMenu()\n }\n }\n\n onDocumentClick(event) {\n if (\n !this.toggleButtonContainer.contains(event.target) &&\n !this.container.contains(event.target)\n ) {\n this.hideMenu()\n }\n }\n}\n"],"names":["SearchToggle","constructor","options","container","search","toggleButtonContainer","toggleButton","hasAttribute","setAttribute","svg","document","createElement","innerHTML","text","addEventListener","onToggleButtonClick","bind","append","onDocumentClick","showMenu","classList","remove","querySelector","focus","hideMenu","add","getAttribute","event","contains","target"],"mappings":"AAAO,MAAMA,YAAY,CAAC;EACxBC,WAAWA,CAACC,OAAO,EAAE;IACnB,IAAI,CAACA,OAAO,GAAGA,OAAO;IACtB,IAAI,CAACC,SAAS,GAAG,IAAI,CAACD,OAAO,CAACE,MAAM,CAACD,SAAS;IAC9C,IAAI,CAACE,qBAAqB,GAAG,IAAI,CAACH,OAAO,CAACI,YAAY,CAACH,SAAS;IAEhE,IAAI,IAAI,CAACA,SAAS,CAACI,YAAY,CAAC,6BAA6B,CAAC,EAAE;AAC9D,MAAA,OAAO,IAAI;AACb;IAEA,IAAI,CAACJ,SAAS,CAACK,YAAY,CAAC,6BAA6B,EAAE,EAAE,CAAC;IAE9D,MAAMC,GAAG,GACP,6pCAA6pC;IAE/pC,IAAI,CAACH,YAAY,GAAGI,QAAQ,CAACC,aAAa,CAAC,QAAQ,CAAC;IACpD,IAAI,CAACL,YAAY,CAACE,YAAY,CAAC,OAAO,EAAE,2BAA2B,CAAC;IACpE,IAAI,CAACF,YAAY,CAACE,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;IAChD,IAAI,CAACF,YAAY,CAACE,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC;IACvD,IAAI,CAACF,YAAY,CAACE,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC;AACxD,IAAA,IAAI,CAACF,YAAY,CAACM,SAAS,GAAG,CAAG,EAAA,IAAI,CAACV,OAAO,CAACI,YAAY,CAACO,IAAI,CAAA,CAAA,EAAIJ,GAAG,CAAE,CAAA;AAExE,IAAA,IAAI,CAACH,YAAY,CAACQ,gBAAgB,CAChC,OAAO,EACP,IAAI,CAACC,mBAAmB,CAACC,IAAI,CAAC,IAAI,CACpC,CAAC;IAED,IAAI,CAACX,qBAAqB,CAACY,MAAM,CAAC,IAAI,CAACX,YAAY,CAAC;AAEpDI,IAAAA,QAAQ,CAACI,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACI,eAAe,CAACF,IAAI,CAAC,IAAI,CAAC,CAAC;AACnEN,IAAAA,QAAQ,CAACI,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAACI,eAAe,CAACF,IAAI,CAAC,IAAI,CAAC,CAAC;AACvE;AAEAG,EAAAA,QAAQA,GAAG;IACT,IAAI,CAACb,YAAY,CAACE,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC;IACvD,IAAI,CAACL,SAAS,CAACiB,SAAS,CAACC,MAAM,CAAC,eAAe,CAAC;IAChD,IAAI,CAAClB,SAAS,CAACmB,aAAa,CAAC,OAAO,CAAC,CAACC,KAAK,EAAE;AAC/C;AAEAC,EAAAA,QAAQA,GAAG;IACT,IAAI,CAACrB,SAAS,CAACiB,SAAS,CAACK,GAAG,CAAC,eAAe,CAAC;IAC7C,IAAI,CAACnB,YAAY,CAACE,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC;AAC1D;AAEAO,EAAAA,mBAAmBA,GAAG;IACpB,IAAI,IAAI,CAACT,YAAY,CAACoB,YAAY,CAAC,eAAe,CAAC,KAAK,OAAO,EAAE;MAC/D,IAAI,CAACP,QAAQ,EAAE;AACjB,KAAC,MAAM;MACL,IAAI,CAACK,QAAQ,EAAE;AACjB;AACF;EAEAN,eAAeA,CAACS,KAAK,EAAE;IACrB,IACE,CAAC,IAAI,CAACtB,qBAAqB,CAACuB,QAAQ,CAACD,KAAK,CAACE,MAAM,CAAC,IAClD,CAAC,IAAI,CAAC1B,SAAS,CAACyB,QAAQ,CAACD,KAAK,CAACE,MAAM,CAAC,EACtC;MACA,IAAI,CAACL,QAAQ,EAAE;AACjB;AACF;AACF;;;;"}
1
+ {"version":3,"file":"search-toggle.mjs","sources":["../../../../src/moj/components/search-toggle/search-toggle.mjs"],"sourcesContent":["import { ConfigurableComponent } from 'govuk-frontend'\n\n/**\n * @augments {ConfigurableComponent<SearchToggleConfig>}\n */\nexport class SearchToggle extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for search toggle\n * @param {SearchToggleConfig} [config] - Search toggle config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n const $searchContainer =\n this.config.searchContainer.element ??\n this.$root.querySelector(this.config.searchContainer.selector)\n\n const $toggleButtonContainer =\n this.config.toggleButtonContainer.element ??\n this.$root.querySelector(this.config.toggleButtonContainer.selector)\n\n if (\n !$searchContainer ||\n !$toggleButtonContainer ||\n !($searchContainer instanceof HTMLElement) ||\n !($toggleButtonContainer instanceof HTMLElement)\n ) {\n return this\n }\n\n this.$searchContainer = $searchContainer\n this.$toggleButtonContainer = $toggleButtonContainer\n\n const svg =\n '<svg viewBox=\"0 0 20 20\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" class=\"moj-search-toggle__button__icon\"><path d=\"M7.433,12.5790048 C6.06762625,12.5808611 4.75763941,12.0392925 3.79217348,11.0738265 C2.82670755,10.1083606 2.28513891,8.79837375 2.28699522,7.433 C2.28513891,6.06762625 2.82670755,4.75763941 3.79217348,3.79217348 C4.75763941,2.82670755 6.06762625,2.28513891 7.433,2.28699522 C8.79837375,2.28513891 10.1083606,2.82670755 11.0738265,3.79217348 C12.0392925,4.75763941 12.5808611,6.06762625 12.5790048,7.433 C12.5808611,8.79837375 12.0392925,10.1083606 11.0738265,11.0738265 C10.1083606,12.0392925 8.79837375,12.5808611 7.433,12.5790048 L7.433,12.5790048 Z M14.293,12.579 L13.391,12.579 L13.071,12.269 C14.2300759,10.9245158 14.8671539,9.20813198 14.866,7.433 C14.866,3.32786745 11.5381325,-1.65045755e-15 7.433,-1.65045755e-15 C3.32786745,-1.65045755e-15 -1.65045755e-15,3.32786745 -1.65045755e-15,7.433 C-1.65045755e-15,11.5381325 3.32786745,14.866 7.433,14.866 C9.208604,14.8671159 10.9253982,14.2296624 12.27,13.07 L12.579,13.39 L12.579,14.294 L18.296,20 L20,18.296 L14.294,12.579 L14.293,12.579 Z\"></path></svg>'\n\n this.$toggleButton = document.createElement('button')\n this.$toggleButton.setAttribute('class', 'moj-search-toggle__button')\n this.$toggleButton.setAttribute('type', 'button')\n this.$toggleButton.setAttribute('aria-haspopup', 'true')\n this.$toggleButton.setAttribute('aria-expanded', 'false')\n this.$toggleButton.innerHTML = `${this.config.toggleButton.text} ${svg}`\n\n this.$toggleButton.addEventListener(\n 'click',\n this.onToggleButtonClick.bind(this)\n )\n\n this.$toggleButtonContainer.append(this.$toggleButton)\n\n document.addEventListener('click', this.onDocumentClick.bind(this))\n document.addEventListener('focusin', this.onDocumentClick.bind(this))\n }\n\n showMenu() {\n this.$toggleButton.setAttribute('aria-expanded', 'true')\n this.$searchContainer.classList.remove('moj-js-hidden')\n this.$searchContainer.querySelector('input').focus()\n }\n\n hideMenu() {\n this.$searchContainer.classList.add('moj-js-hidden')\n this.$toggleButton.setAttribute('aria-expanded', 'false')\n }\n\n onToggleButtonClick() {\n if (this.$toggleButton.getAttribute('aria-expanded') === 'false') {\n this.showMenu()\n } else {\n this.hideMenu()\n }\n }\n\n /**\n * @param {MouseEvent | FocusEvent} event\n */\n onDocumentClick(event) {\n if (\n event.target instanceof Node &&\n !this.$toggleButtonContainer.contains(event.target) &&\n !this.$searchContainer.contains(event.target)\n ) {\n this.hideMenu()\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-search-toggle'\n\n /**\n * Search toggle config\n *\n * @type {SearchToggleConfig}\n */\n static defaults = Object.freeze({\n searchContainer: {\n selector: '.moj-search'\n },\n toggleButton: {\n text: 'Search'\n },\n toggleButtonContainer: {\n selector: '.moj-search-toggle__toggle'\n }\n })\n\n /**\n * Search toggle config schema\n *\n * @satisfies {Schema<SearchToggleConfig>}\n */\n static schema = Object.freeze(\n /** @type {const} */ ({\n properties: {\n searchContainer: { type: 'object' },\n toggleButton: { type: 'object' },\n toggleButtonContainer: { type: 'object' }\n }\n })\n )\n}\n\n/**\n * @typedef {object} SearchToggleConfig\n * @property {object} [searchContainer] - Search config\n * @property {string} [searchContainer.selector] - Selector for search container\n * @property {Element | null} [searchContainer.element] - HTML element for search container\n * @property {object} [toggleButton] - Toggle button config\n * @property {string} [toggleButton.text] - Text for toggle button\n * @property {object} [toggleButtonContainer] - Toggle button container config\n * @property {string} [toggleButtonContainer.selector] - Selector for toggle button container\n * @property {Element | null} [toggleButtonContainer.element] - HTML element for toggle button container\n */\n\n/**\n * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'\n */\n"],"names":["SearchToggle","ConfigurableComponent","constructor","$root","config","_this$config$searchCo","_this$config$toggleBu","$searchContainer","searchContainer","element","querySelector","selector","$toggleButtonContainer","toggleButtonContainer","HTMLElement","svg","$toggleButton","document","createElement","setAttribute","innerHTML","toggleButton","text","addEventListener","onToggleButtonClick","bind","append","onDocumentClick","showMenu","classList","remove","focus","hideMenu","add","getAttribute","event","target","Node","contains","moduleName","defaults","Object","freeze","schema","properties","type"],"mappings":"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"}
@@ -2,9 +2,10 @@
2
2
 
3
3
  [aria-sort] button,
4
4
  [aria-sort] button:hover {
5
+ display: inline-flex;
5
6
  position: relative;
6
7
  margin: 0;
7
- padding: 0 10px 0 0;
8
+ padding: 0;
8
9
  border-width: 0;
9
10
  color: #005ea5;
10
11
  background-color: transparent;
@@ -15,6 +16,7 @@
15
16
  font-weight: inherit;
16
17
  text-align: inherit;
17
18
  cursor: pointer;
19
+ align-items: center;
18
20
  }
19
21
 
20
22
  [aria-sort] button:focus {
@@ -26,45 +28,4 @@
26
28
  0 4px $govuk-focus-text-colour;
27
29
  }
28
30
 
29
- [aria-sort]:first-child button {
30
- right: auto;
31
- }
32
-
33
- [aria-sort] button::before {
34
- content: " \25bc";
35
- position: absolute;
36
- top: 9px;
37
- right: -1px;
38
- font-size: 0.5em;
39
- }
40
-
41
- [aria-sort] button::after {
42
- content: " \25b2";
43
- position: absolute;
44
- top: 1px;
45
- right: -1px;
46
- font-size: 0.5em;
47
- }
48
-
49
- [aria-sort="ascending"] button::before,
50
- [aria-sort="descending"] button::before {
51
- content: none;
52
- }
53
-
54
- [aria-sort="ascending"] button::after {
55
- content: " \25b2";
56
- position: absolute;
57
- top: 2px;
58
- right: -5px;
59
- font-size: 0.8em;
60
- }
61
-
62
- [aria-sort="descending"] button::after {
63
- content: " \25bc";
64
- position: absolute;
65
- top: 2px;
66
- right: -5px;
67
- font-size: 0.8em;
68
- }
69
-
70
31
  /*# sourceMappingURL=_sortable-table.scss.map */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/moj/components/sortable-table/_sortable-table.scss"],"names":[],"mappings":"AAAA,uCAAuC;;AAEvC;;EAEE,kBAAkB;EAClB,SAAS;EACT,mBAAmB;EACnB,eAAe;EACf,cAAc;EACd,6BAA6B;EAG7B,mBAAmB;EACnB,oBAAoB;EACpB,kBAAkB;EAClB,cAAc;EACd,oBAAoB;EACpB,mBAAmB;EACnB,eAAe;AACjB;;AAEA;EACE,aAAa;EACb,+BAA+B;EAC/B,qCAAqC;EACrC;;kCAEgC;AAClC;;AAEA;EACE,WAAW;AACb;;AAEA;EACE,iBAAiB;EACjB,kBAAkB;EAClB,QAAQ;EACR,WAAW;EACX,gBAAgB;AAClB;;AAEA;EACE,iBAAiB;EACjB,kBAAkB;EAClB,QAAQ;EACR,WAAW;EACX,gBAAgB;AAClB;;AAEA;;EAEE,aAAa;AACf;;AAEA;EACE,iBAAiB;EACjB,kBAAkB;EAClB,QAAQ;EACR,WAAW;EACX,gBAAgB;AAClB;;AAEA;EACE,iBAAiB;EACjB,kBAAkB;EAClB,QAAQ;EACR,WAAW;EACX,gBAAgB;AAClB","file":"_sortable-table.scss","sourcesContent":["@use \"../../vendor/govuk-frontend\" as *;\n\n[aria-sort] button,\n[aria-sort] button:hover {\n position: relative;\n margin: 0;\n padding: 0 10px 0 0;\n border-width: 0;\n color: #005ea5;\n background-color: transparent;\n -webkit-box-shadow: 0 0 0 0;\n -moz-box-shadow: 0 0 0 0;\n box-shadow: 0 0 0 0;\n font-family: inherit;\n font-size: inherit;\n font-size: 1em;\n font-weight: inherit;\n text-align: inherit;\n cursor: pointer;\n}\n\n[aria-sort] button:focus {\n outline: none;\n color: $govuk-focus-text-colour;\n background-color: $govuk-focus-colour;\n box-shadow:\n 0 -2px $govuk-focus-colour,\n 0 4px $govuk-focus-text-colour;\n}\n\n[aria-sort]:first-child button {\n right: auto;\n}\n\n[aria-sort] button::before {\n content: \" \\25bc\";\n position: absolute;\n top: 9px;\n right: -1px;\n font-size: 0.5em;\n}\n\n[aria-sort] button::after {\n content: \" \\25b2\";\n position: absolute;\n top: 1px;\n right: -1px;\n font-size: 0.5em;\n}\n\n[aria-sort=\"ascending\"] button::before,\n[aria-sort=\"descending\"] button::before {\n content: none;\n}\n\n[aria-sort=\"ascending\"] button::after {\n content: \" \\25b2\";\n position: absolute;\n top: 2px;\n right: -5px;\n font-size: 0.8em;\n}\n\n[aria-sort=\"descending\"] button::after {\n content: \" \\25bc\";\n position: absolute;\n top: 2px;\n right: -5px;\n font-size: 0.8em;\n}\n"]}
1
+ {"version":3,"sources":["../../../../src/moj/components/sortable-table/_sortable-table.scss"],"names":[],"mappings":"AAAA,uCAAuC;;AAEvC;;EAEE,oBAAoB;EACpB,kBAAkB;EAClB,SAAS;EACT,UAAU;EACV,eAAe;EACf,cAAc;EACd,6BAA6B;EAG7B,mBAAmB;EACnB,oBAAoB;EACpB,kBAAkB;EAClB,cAAc;EACd,oBAAoB;EACpB,mBAAmB;EACnB,eAAe;EACf,mBAAmB;AACrB;;AAEA;EACE,aAAa;EACb,+BAA+B;EAC/B,qCAAqC;EACrC;;kCAEgC;AAClC","file":"_sortable-table.scss","sourcesContent":["@use \"../../vendor/govuk-frontend\" as *;\n\n[aria-sort] button,\n[aria-sort] button:hover {\n display: inline-flex;\n position: relative;\n margin: 0;\n padding: 0;\n border-width: 0;\n color: #005ea5;\n background-color: transparent;\n -webkit-box-shadow: 0 0 0 0;\n -moz-box-shadow: 0 0 0 0;\n box-shadow: 0 0 0 0;\n font-family: inherit;\n font-size: inherit;\n font-size: 1em;\n font-weight: inherit;\n text-align: inherit;\n cursor: pointer;\n align-items: center;\n}\n\n[aria-sort] button:focus {\n outline: none;\n color: $govuk-focus-text-colour;\n background-color: $govuk-focus-colour;\n box-shadow:\n 0 -2px $govuk-focus-colour,\n 0 4px $govuk-focus-text-colour;\n}\n"]}
@@ -1,133 +1,250 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MOJFrontend = global.MOJFrontend || {}));
5
- })(this, (function (exports) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('govuk-frontend')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'govuk-frontend'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MOJFrontend = global.MOJFrontend || {}, global.GOVUKFrontend));
5
+ })(this, (function (exports, govukFrontend) { 'use strict';
6
6
 
7
- class SortableTable {
8
- constructor(params) {
9
- const table = params.table;
10
- const head = table == null ? void 0 : table.querySelector('thead');
11
- const body = table == null ? void 0 : table.querySelector('tbody');
12
- if (!table || !(table instanceof HTMLElement) || !head || !body) {
7
+ /**
8
+ * @augments {ConfigurableComponent<SortableTableConfig>}
9
+ */
10
+ class SortableTable extends govukFrontend.ConfigurableComponent {
11
+ /**
12
+ * @param {Element | null} $root - HTML element to use for sortable table
13
+ * @param {SortableTableConfig} [config] - Sortable table config
14
+ */
15
+ constructor($root, config = {}) {
16
+ super($root, config);
17
+ const $head = $root == null ? void 0 : $root.querySelector('thead');
18
+ const $body = $root == null ? void 0 : $root.querySelector('tbody');
19
+ if (!$head || !$body) {
13
20
  return this;
14
21
  }
15
- this.table = table;
16
- this.head = head;
17
- this.body = body;
18
- if (this.table.hasAttribute('data-moj-sortable-table-init')) {
19
- return this;
20
- }
21
- this.table.setAttribute('data-moj-sortable-table-init', '');
22
- this.headings = this.head ? Array.from(this.head.querySelectorAll('th')) : [];
23
- this.setupOptions(params);
22
+ this.$head = $head;
23
+ this.$body = $body;
24
+ this.$caption = this.$root.querySelector('caption');
25
+ this.$upArrow = `<svg width="22" height="22" focusable="false" aria-hidden="true" role="img" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
26
+ <path d="M6.5625 15.5L11 6.63125L15.4375 15.5H6.5625Z" fill="currentColor"/>
27
+ </svg>`;
28
+ this.$downArrow = `<svg width="22" height="22" focusable="false" aria-hidden="true" role="img" vviewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
29
+ <path d="M15.4375 7L11 15.8687L6.5625 7L15.4375 7Z" fill="currentColor"/>
30
+ </svg>`;
31
+ this.$upDownArrow = `<svg width="22" height="22" focusable="false" aria-hidden="true" role="img" vviewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
32
+ <path d="M8.1875 9.5L10.9609 3.95703L13.7344 9.5H8.1875Z" fill="currentColor"/>
33
+ <path d="M13.7344 12.0781L10.9609 17.6211L8.1875 12.0781H13.7344Z" fill="currentColor"/>
34
+ </svg>`;
35
+ this.$headings = this.$head ? Array.from(this.$head.querySelectorAll('th')) : [];
24
36
  this.createHeadingButtons();
37
+ this.updateCaption();
38
+ this.updateDirectionIndicators();
25
39
  this.createStatusBox();
26
40
  this.initialiseSortedColumn();
27
- this.head.addEventListener('click', this.onSortButtonClick.bind(this));
28
- }
29
- setupOptions(params) {
30
- params = params || {};
31
- this.statusMessage = params.statusMessage || 'Sort by %heading% (%direction%)';
32
- this.ascendingText = params.ascendingText || 'ascending';
33
- this.descendingText = params.descendingText || 'descending';
41
+ this.$head.addEventListener('click', this.onSortButtonClick.bind(this));
34
42
  }
35
43
  createHeadingButtons() {
36
- for (const heading of this.headings) {
37
- if (heading.hasAttribute('aria-sort')) {
38
- this.createHeadingButton(heading);
44
+ for (const $heading of this.$headings) {
45
+ if ($heading.hasAttribute('aria-sort')) {
46
+ this.createHeadingButton($heading);
39
47
  }
40
48
  }
41
49
  }
42
- createHeadingButton(heading) {
43
- const index = this.headings.indexOf(heading);
44
- const button = document.createElement('button');
45
- button.setAttribute('type', 'button');
46
- button.setAttribute('data-index', `${index}`);
47
- button.textContent = heading.textContent;
48
- heading.textContent = '';
49
- heading.appendChild(button);
50
+
51
+ /**
52
+ * @param {HTMLTableCellElement} $heading
53
+ */
54
+ createHeadingButton($heading) {
55
+ const index = this.$headings.indexOf($heading);
56
+ const $button = document.createElement('button');
57
+ $button.setAttribute('type', 'button');
58
+ $button.setAttribute('data-index', `${index}`);
59
+ $button.textContent = $heading.textContent;
60
+ $heading.textContent = '';
61
+ $heading.appendChild($button);
50
62
  }
51
63
  createStatusBox() {
52
- this.status = document.createElement('div');
53
- this.status.setAttribute('aria-atomic', 'true');
54
- this.status.setAttribute('aria-live', 'polite');
55
- this.status.setAttribute('class', 'govuk-visually-hidden');
56
- this.status.setAttribute('role', 'status');
57
- this.table.insertAdjacentElement('afterend', this.status);
64
+ this.$status = document.createElement('div');
65
+ this.$status.setAttribute('aria-atomic', 'true');
66
+ this.$status.setAttribute('aria-live', 'polite');
67
+ this.$status.setAttribute('class', 'govuk-visually-hidden');
68
+ this.$status.setAttribute('role', 'status');
69
+ this.$root.insertAdjacentElement('afterend', this.$status);
58
70
  }
59
71
  initialiseSortedColumn() {
60
- var _sortButton$getAttrib;
61
- const rows = this.getTableRowsArray();
62
- const heading = this.table.querySelector('th[aria-sort]');
63
- const sortButton = heading == null ? void 0 : heading.querySelector('button');
64
- const sortDirection = heading == null ? void 0 : heading.getAttribute('aria-sort');
65
- const columnNumber = Number.parseInt((_sortButton$getAttrib = sortButton == null ? void 0 : sortButton.getAttribute('data-index')) != null ? _sortButton$getAttrib : '0', 10);
66
- if (!heading || !sortButton || !(sortDirection === 'ascending' || sortDirection === 'descending')) {
72
+ var _$sortButton$getAttri;
73
+ const $rows = this.getTableRowsArray();
74
+ const $heading = this.$root.querySelector('th[aria-sort="ascending"], th[aria-sort="descending"]');
75
+ const $sortButton = $heading == null ? void 0 : $heading.querySelector('button');
76
+ const sortDirection = $heading == null ? void 0 : $heading.getAttribute('aria-sort');
77
+ const columnNumber = Number.parseInt((_$sortButton$getAttri = $sortButton == null ? void 0 : $sortButton.getAttribute('data-index')) != null ? _$sortButton$getAttri : '0', 10);
78
+ if (!$heading || !$sortButton || !(sortDirection === 'ascending' || sortDirection === 'descending')) {
67
79
  return;
68
80
  }
69
- const sortedRows = this.sort(rows, columnNumber, sortDirection);
70
- this.addRows(sortedRows);
81
+ const $sortedRows = this.sort($rows, columnNumber, sortDirection);
82
+ this.addRows($sortedRows);
71
83
  }
84
+
85
+ /**
86
+ * @param {MouseEvent} event - Click event
87
+ */
72
88
  onSortButtonClick(event) {
73
- var _button$getAttribute;
74
- const button = event.target;
75
- if (!button || !(button instanceof HTMLButtonElement) || !button.parentElement) {
89
+ var _$button$getAttribute;
90
+ const $target = /** @type {HTMLElement} */event.target;
91
+ const $button = $target.closest('button');
92
+ if (!$button || !($button instanceof HTMLButtonElement) || !$button.parentElement) {
76
93
  return;
77
94
  }
78
- const heading = button.parentElement;
79
- const sortDirection = heading.getAttribute('aria-sort');
80
- const columnNumber = Number.parseInt((_button$getAttribute = button == null ? void 0 : button.getAttribute('data-index')) != null ? _button$getAttribute : '0', 10);
95
+ const $heading = $button.parentElement;
96
+ const sortDirection = $heading.getAttribute('aria-sort');
97
+ const columnNumber = Number.parseInt((_$button$getAttribute = $button == null ? void 0 : $button.getAttribute('data-index')) != null ? _$button$getAttribute : '0', 10);
81
98
  const newSortDirection = sortDirection === 'none' || sortDirection === 'descending' ? 'ascending' : 'descending';
82
- const rows = this.getTableRowsArray();
83
- const sortedRows = this.sort(rows, columnNumber, newSortDirection);
84
- this.addRows(sortedRows);
99
+ const $rows = this.getTableRowsArray();
100
+ const $sortedRows = this.sort($rows, columnNumber, newSortDirection);
101
+ this.addRows($sortedRows);
85
102
  this.removeButtonStates();
86
- this.updateButtonState(button, newSortDirection);
103
+ this.updateButtonState($button, newSortDirection);
104
+ this.updateDirectionIndicators();
87
105
  }
88
- updateButtonState(button, direction) {
106
+ updateCaption() {
107
+ if (!this.$caption) {
108
+ return;
109
+ }
110
+ let assistiveText = this.$caption.querySelector('.govuk-visually-hidden');
111
+ if (assistiveText) {
112
+ return;
113
+ }
114
+ assistiveText = document.createElement('span');
115
+ assistiveText.classList.add('govuk-visually-hidden');
116
+ assistiveText.textContent = ' (column headers with buttons are sortable).';
117
+ this.$caption.appendChild(assistiveText);
118
+ }
119
+
120
+ /**
121
+ * @param {HTMLButtonElement} $button
122
+ * @param {string} direction
123
+ */
124
+ updateButtonState($button, direction) {
89
125
  if (!(direction === 'ascending' || direction === 'descending')) {
90
126
  return;
91
127
  }
92
- button.parentElement.setAttribute('aria-sort', direction);
93
- let message = this.statusMessage;
94
- message = message.replace(/%heading%/, button.textContent);
95
- message = message.replace(/%direction%/, this[`${direction}Text`]);
96
- this.status.textContent = message;
128
+ $button.parentElement.setAttribute('aria-sort', direction);
129
+ let message = this.config.statusMessage;
130
+ message = message.replace(/%heading%/, $button.textContent);
131
+ message = message.replace(/%direction%/, this.config[`${direction}Text`]);
132
+ this.$status.textContent = message;
133
+ }
134
+ updateDirectionIndicators() {
135
+ for (const $heading of this.$headings) {
136
+ const $button = /** @type {HTMLButtonElement} */
137
+ $heading.querySelector('button');
138
+ if ($heading.hasAttribute('aria-sort') && $button) {
139
+ var _$button$querySelecto;
140
+ const direction = $heading.getAttribute('aria-sort');
141
+ (_$button$querySelecto = $button.querySelector('svg')) == null || _$button$querySelecto.remove();
142
+ switch (direction) {
143
+ case 'ascending':
144
+ $button.insertAdjacentHTML('beforeend', this.$upArrow);
145
+ break;
146
+ case 'descending':
147
+ $button.insertAdjacentHTML('beforeend', this.$downArrow);
148
+ break;
149
+ default:
150
+ $button.insertAdjacentHTML('beforeend', this.$upDownArrow);
151
+ }
152
+ }
153
+ }
97
154
  }
98
155
  removeButtonStates() {
99
- for (const heading of this.headings) {
100
- heading.setAttribute('aria-sort', 'none');
156
+ for (const $heading of this.$headings) {
157
+ $heading.setAttribute('aria-sort', 'none');
101
158
  }
102
159
  }
103
- addRows(rows) {
104
- for (const row of rows) {
105
- this.body.append(row);
160
+
161
+ /**
162
+ * @param {HTMLTableRowElement[]} $rows
163
+ */
164
+ addRows($rows) {
165
+ for (const $row of $rows) {
166
+ this.$body.append($row);
106
167
  }
107
168
  }
108
169
  getTableRowsArray() {
109
- return Array.from(this.body.querySelectorAll('tr'));
170
+ return Array.from(this.$body.querySelectorAll('tr'));
110
171
  }
111
- sort(rows, columnNumber, sortDirection) {
112
- return rows.sort((rowA, rowB) => {
113
- const tdA = rowA.querySelectorAll('td, th')[columnNumber];
114
- const tdB = rowB.querySelectorAll('td, th')[columnNumber];
115
- if (!tdA || !tdB || !(tdA instanceof HTMLElement) || !(tdB instanceof HTMLElement)) {
172
+
173
+ /**
174
+ * @param {HTMLTableRowElement[]} $rows
175
+ * @param {number} columnNumber
176
+ * @param {string} sortDirection
177
+ */
178
+ sort($rows, columnNumber, sortDirection) {
179
+ return $rows.sort(($rowA, $rowB) => {
180
+ const $tdA = $rowA.querySelectorAll('td, th')[columnNumber];
181
+ const $tdB = $rowB.querySelectorAll('td, th')[columnNumber];
182
+ if (!$tdA || !$tdB || !($tdA instanceof HTMLElement) || !($tdB instanceof HTMLElement)) {
116
183
  return 0;
117
184
  }
118
- const valueA = sortDirection === 'ascending' ? this.getCellValue(tdA) : this.getCellValue(tdB);
119
- const valueB = sortDirection === 'ascending' ? this.getCellValue(tdB) : this.getCellValue(tdA);
185
+ const valueA = sortDirection === 'ascending' ? this.getCellValue($tdA) : this.getCellValue($tdB);
186
+ const valueB = sortDirection === 'ascending' ? this.getCellValue($tdB) : this.getCellValue($tdA);
120
187
  return !(typeof valueA === 'number' && typeof valueB === 'number') ? valueA.toString().localeCompare(valueB.toString()) : valueA - valueB;
121
188
  });
122
189
  }
123
- getCellValue(cell) {
124
- const val = cell.getAttribute('data-sort-value') || cell.innerHTML;
190
+
191
+ /**
192
+ * @param {HTMLElement} $cell
193
+ */
194
+ getCellValue($cell) {
195
+ const val = $cell.getAttribute('data-sort-value') || $cell.innerHTML;
125
196
  const valAsNumber = Number(val);
126
197
  return Number.isFinite(valAsNumber) ? valAsNumber // Exclude invalid numbers, infinity etc
127
198
  : val;
128
199
  }
200
+
201
+ /**
202
+ * Name for the component used when initialising using data-module attributes.
203
+ */
129
204
  }
130
205
 
206
+ /**
207
+ * Sortable table config
208
+ *
209
+ * @typedef {object} SortableTableConfig
210
+ * @property {string} [statusMessage] - Status message
211
+ * @property {string} [ascendingText] - Ascending text
212
+ * @property {string} [descendingText] - Descending text
213
+ */
214
+
215
+ /**
216
+ * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
217
+ */
218
+ SortableTable.moduleName = 'moj-sortable-table';
219
+ /**
220
+ * Sortable table config
221
+ *
222
+ * @type {SortableTableConfig}
223
+ */
224
+ SortableTable.defaults = Object.freeze({
225
+ statusMessage: 'Sort by %heading% (%direction%)',
226
+ ascendingText: 'ascending',
227
+ descendingText: 'descending'
228
+ });
229
+ /**
230
+ * Sortable table config schema
231
+ *
232
+ * @satisfies {Schema<SortableTableConfig>}
233
+ */
234
+ SortableTable.schema = Object.freeze(/** @type {const} */{
235
+ properties: {
236
+ statusMessage: {
237
+ type: 'string'
238
+ },
239
+ ascendingText: {
240
+ type: 'string'
241
+ },
242
+ descendingText: {
243
+ type: 'string'
244
+ }
245
+ }
246
+ });
247
+
131
248
  exports.SortableTable = SortableTable;
132
249
 
133
250
  }));