@ministryofjustice/frontend 5.0.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/moj/all.bundle.js +1549 -1062
  2. package/moj/all.bundle.js.map +1 -1
  3. package/moj/all.bundle.mjs +1845 -1054
  4. package/moj/all.bundle.mjs.map +1 -1
  5. package/moj/all.mjs +7 -90
  6. package/moj/all.mjs.map +1 -1
  7. package/moj/all.scss +1 -0
  8. package/moj/all.scss.map +1 -1
  9. package/moj/common/index.mjs +57 -0
  10. package/moj/common/index.mjs.map +1 -0
  11. package/moj/common/moj-frontend-version.mjs +14 -0
  12. package/moj/common/moj-frontend-version.mjs.map +1 -0
  13. package/moj/components/add-another/add-another.bundle.js +105 -76
  14. package/moj/components/add-another/add-another.bundle.js.map +1 -1
  15. package/moj/components/add-another/add-another.bundle.mjs +222 -71
  16. package/moj/components/add-another/add-another.bundle.mjs.map +1 -1
  17. package/moj/components/add-another/add-another.mjs +103 -72
  18. package/moj/components/add-another/add-another.mjs.map +1 -1
  19. package/moj/components/alert/alert.bundle.js +115 -191
  20. package/moj/components/alert/alert.bundle.js.map +1 -1
  21. package/moj/components/alert/alert.bundle.mjs +354 -186
  22. package/moj/components/alert/alert.bundle.mjs.map +1 -1
  23. package/moj/components/alert/alert.mjs +55 -140
  24. package/moj/components/alert/alert.mjs.map +1 -1
  25. package/moj/components/button-menu/README.md +3 -1
  26. package/moj/components/button-menu/button-menu.bundle.js +91 -120
  27. package/moj/components/button-menu/button-menu.bundle.js.map +1 -1
  28. package/moj/components/button-menu/button-menu.bundle.mjs +329 -114
  29. package/moj/components/button-menu/button-menu.bundle.mjs.map +1 -1
  30. package/moj/components/button-menu/button-menu.mjs +89 -116
  31. package/moj/components/button-menu/button-menu.mjs.map +1 -1
  32. package/moj/components/date-picker/date-picker.bundle.js +174 -154
  33. package/moj/components/date-picker/date-picker.bundle.js.map +1 -1
  34. package/moj/components/date-picker/date-picker.bundle.mjs +411 -147
  35. package/moj/components/date-picker/date-picker.bundle.mjs.map +1 -1
  36. package/moj/components/date-picker/date-picker.mjs +172 -150
  37. package/moj/components/date-picker/date-picker.mjs.map +1 -1
  38. package/moj/components/filter/template.njk +1 -1
  39. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js +133 -44
  40. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js.map +1 -1
  41. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs +374 -41
  42. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs.map +1 -1
  43. package/moj/components/filter-toggle-button/filter-toggle-button.mjs +131 -40
  44. package/moj/components/filter-toggle-button/filter-toggle-button.mjs.map +1 -1
  45. package/moj/components/form-validator/form-validator.bundle.js +159 -69
  46. package/moj/components/form-validator/form-validator.bundle.js.map +1 -1
  47. package/moj/components/form-validator/form-validator.bundle.mjs +399 -65
  48. package/moj/components/form-validator/form-validator.bundle.mjs.map +1 -1
  49. package/moj/components/form-validator/form-validator.mjs +134 -54
  50. package/moj/components/form-validator/form-validator.mjs.map +1 -1
  51. package/moj/components/multi-file-upload/multi-file-upload.bundle.js +291 -117
  52. package/moj/components/multi-file-upload/multi-file-upload.bundle.js.map +1 -1
  53. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs +527 -109
  54. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs.map +1 -1
  55. package/moj/components/multi-file-upload/multi-file-upload.mjs +288 -101
  56. package/moj/components/multi-file-upload/multi-file-upload.mjs.map +1 -1
  57. package/moj/components/multi-file-upload/template.njk +1 -1
  58. package/moj/components/multi-select/multi-select.bundle.js +106 -41
  59. package/moj/components/multi-select/multi-select.bundle.js.map +1 -1
  60. package/moj/components/multi-select/multi-select.bundle.mjs +346 -37
  61. package/moj/components/multi-select/multi-select.bundle.mjs.map +1 -1
  62. package/moj/components/multi-select/multi-select.mjs +104 -37
  63. package/moj/components/multi-select/multi-select.mjs.map +1 -1
  64. package/moj/components/password-reveal/_password-reveal.scss +3 -1
  65. package/moj/components/password-reveal/_password-reveal.scss.map +1 -1
  66. package/moj/components/password-reveal/password-reveal.bundle.js +32 -29
  67. package/moj/components/password-reveal/password-reveal.bundle.js.map +1 -1
  68. package/moj/components/password-reveal/password-reveal.bundle.mjs +149 -24
  69. package/moj/components/password-reveal/password-reveal.bundle.mjs.map +1 -1
  70. package/moj/components/password-reveal/password-reveal.mjs +30 -25
  71. package/moj/components/password-reveal/password-reveal.mjs.map +1 -1
  72. package/moj/components/rich-text-editor/README.md +4 -3
  73. package/moj/components/rich-text-editor/rich-text-editor.bundle.js +127 -62
  74. package/moj/components/rich-text-editor/rich-text-editor.bundle.js.map +1 -1
  75. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs +367 -58
  76. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs.map +1 -1
  77. package/moj/components/rich-text-editor/rich-text-editor.mjs +125 -58
  78. package/moj/components/rich-text-editor/rich-text-editor.mjs.map +1 -1
  79. package/moj/components/search-toggle/search-toggle.bundle.js +94 -26
  80. package/moj/components/search-toggle/search-toggle.bundle.js.map +1 -1
  81. package/moj/components/search-toggle/search-toggle.bundle.mjs +334 -22
  82. package/moj/components/search-toggle/search-toggle.bundle.mjs.map +1 -1
  83. package/moj/components/search-toggle/search-toggle.mjs +92 -22
  84. package/moj/components/search-toggle/search-toggle.mjs.map +1 -1
  85. package/moj/components/sortable-table/sortable-table.bundle.js +151 -83
  86. package/moj/components/sortable-table/sortable-table.bundle.js.map +1 -1
  87. package/moj/components/sortable-table/sortable-table.bundle.mjs +390 -78
  88. package/moj/components/sortable-table/sortable-table.bundle.mjs.map +1 -1
  89. package/moj/components/sortable-table/sortable-table.mjs +149 -79
  90. package/moj/components/sortable-table/sortable-table.mjs.map +1 -1
  91. package/moj/core/_all.scss +3 -0
  92. package/moj/core/_all.scss.map +1 -0
  93. package/moj/core/_moj-frontend-properties.scss +7 -0
  94. package/moj/core/_moj-frontend-properties.scss.map +1 -0
  95. package/moj/filters/prototype-kit-13-filters.js +4 -3
  96. package/moj/helpers.bundle.js +22 -77
  97. package/moj/helpers.bundle.js.map +1 -1
  98. package/moj/helpers.bundle.mjs +23 -74
  99. package/moj/helpers.bundle.mjs.map +1 -1
  100. package/moj/helpers.mjs +23 -74
  101. package/moj/helpers.mjs.map +1 -1
  102. package/moj/moj-frontend.min.css +1 -1
  103. package/moj/moj-frontend.min.css.map +1 -1
  104. package/moj/moj-frontend.min.js +1 -1
  105. package/moj/moj-frontend.min.js.map +1 -1
  106. package/package.json +1 -1
  107. package/moj/version.bundle.js +0 -12
  108. package/moj/version.bundle.js.map +0 -1
  109. package/moj/version.bundle.mjs +0 -4
  110. package/moj/version.bundle.mjs.map +0 -1
  111. package/moj/version.mjs +0 -4
  112. package/moj/version.mjs.map +0 -1
@@ -1,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":";;AAEA;AACA;AACA;AACO,MAAMA,YAAY,SAASC,qBAAqB,CAAC;AACtD;AACF;AACA;AACA;AACEC,EAAAA,WAAWA,CAACC,KAAK,EAAEC,MAAM,GAAG,EAAE,EAAE;IAAA,IAAAC,qBAAA,EAAAC,qBAAA;AAC9B,IAAA,KAAK,CAACH,KAAK,EAAEC,MAAM,CAAC;IAEpB,MAAMG,gBAAgB,GAAAF,CAAAA,qBAAA,GACpB,IAAI,CAACD,MAAM,CAACI,eAAe,CAACC,OAAO,KAAAJ,IAAAA,GAAAA,qBAAA,GACnC,IAAI,CAACF,KAAK,CAACO,aAAa,CAAC,IAAI,CAACN,MAAM,CAACI,eAAe,CAACG,QAAQ,CAAC;IAEhE,MAAMC,sBAAsB,GAAAN,CAAAA,qBAAA,GAC1B,IAAI,CAACF,MAAM,CAACS,qBAAqB,CAACJ,OAAO,KAAAH,IAAAA,GAAAA,qBAAA,GACzC,IAAI,CAACH,KAAK,CAACO,aAAa,CAAC,IAAI,CAACN,MAAM,CAACS,qBAAqB,CAACF,QAAQ,CAAC;AAEtE,IAAA,IACE,CAACJ,gBAAgB,IACjB,CAACK,sBAAsB,IACvB,EAAEL,gBAAgB,YAAYO,WAAW,CAAC,IAC1C,EAAEF,sBAAsB,YAAYE,WAAW,CAAC,EAChD;AACA,MAAA,OAAO,IAAI;AACb;IAEA,IAAI,CAACP,gBAAgB,GAAGA,gBAAgB;IACxC,IAAI,CAACK,sBAAsB,GAAGA,sBAAsB;IAEpD,MAAMG,GAAG,GACP,6pCAA6pC;IAE/pC,IAAI,CAACC,aAAa,GAAGC,QAAQ,CAACC,aAAa,CAAC,QAAQ,CAAC;IACrD,IAAI,CAACF,aAAa,CAACG,YAAY,CAAC,OAAO,EAAE,2BAA2B,CAAC;IACrE,IAAI,CAACH,aAAa,CAACG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;IACjD,IAAI,CAACH,aAAa,CAACG,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC;IACxD,IAAI,CAACH,aAAa,CAACG,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC;AACzD,IAAA,IAAI,CAACH,aAAa,CAACI,SAAS,GAAG,CAAG,EAAA,IAAI,CAAChB,MAAM,CAACiB,YAAY,CAACC,IAAI,CAAA,CAAA,EAAIP,GAAG,CAAE,CAAA;AAExE,IAAA,IAAI,CAACC,aAAa,CAACO,gBAAgB,CACjC,OAAO,EACP,IAAI,CAACC,mBAAmB,CAACC,IAAI,CAAC,IAAI,CACpC,CAAC;IAED,IAAI,CAACb,sBAAsB,CAACc,MAAM,CAAC,IAAI,CAACV,aAAa,CAAC;AAEtDC,IAAAA,QAAQ,CAACM,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACI,eAAe,CAACF,IAAI,CAAC,IAAI,CAAC,CAAC;AACnER,IAAAA,QAAQ,CAACM,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAACI,eAAe,CAACF,IAAI,CAAC,IAAI,CAAC,CAAC;AACvE;AAEAG,EAAAA,QAAQA,GAAG;IACT,IAAI,CAACZ,aAAa,CAACG,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC;IACxD,IAAI,CAACZ,gBAAgB,CAACsB,SAAS,CAACC,MAAM,CAAC,eAAe,CAAC;IACvD,IAAI,CAACvB,gBAAgB,CAACG,aAAa,CAAC,OAAO,CAAC,CAACqB,KAAK,EAAE;AACtD;AAEAC,EAAAA,QAAQA,GAAG;IACT,IAAI,CAACzB,gBAAgB,CAACsB,SAAS,CAACI,GAAG,CAAC,eAAe,CAAC;IACpD,IAAI,CAACjB,aAAa,CAACG,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC;AAC3D;AAEAK,EAAAA,mBAAmBA,GAAG;IACpB,IAAI,IAAI,CAACR,aAAa,CAACkB,YAAY,CAAC,eAAe,CAAC,KAAK,OAAO,EAAE;MAChE,IAAI,CAACN,QAAQ,EAAE;AACjB,KAAC,MAAM;MACL,IAAI,CAACI,QAAQ,EAAE;AACjB;AACF;;AAEA;AACF;AACA;EACEL,eAAeA,CAACQ,KAAK,EAAE;AACrB,IAAA,IACEA,KAAK,CAACC,MAAM,YAAYC,IAAI,IAC5B,CAAC,IAAI,CAACzB,sBAAsB,CAAC0B,QAAQ,CAACH,KAAK,CAACC,MAAM,CAAC,IACnD,CAAC,IAAI,CAAC7B,gBAAgB,CAAC+B,QAAQ,CAACH,KAAK,CAACC,MAAM,CAAC,EAC7C;MACA,IAAI,CAACJ,QAAQ,EAAE;AACjB;AACF;;AAEA;AACF;AACA;AAkCA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AArIahC,YAAY,CAoFhBuC,UAAU,GAAG,mBAAmB;AAEvC;AACF;AACA;AACA;AACA;AA1FavC,YAAY,CA2FhBwC,QAAQ,GAAGC,MAAM,CAACC,MAAM,CAAC;AAC9BlC,EAAAA,eAAe,EAAE;AACfG,IAAAA,QAAQ,EAAE;GACX;AACDU,EAAAA,YAAY,EAAE;AACZC,IAAAA,IAAI,EAAE;GACP;AACDT,EAAAA,qBAAqB,EAAE;AACrBF,IAAAA,QAAQ,EAAE;AACZ;AACF,CAAC,CAAC;AAEF;AACF;AACA;AACA;AACA;AA3GaX,YAAY,CA4GhB2C,MAAM,GAAGF,MAAM,CAACC,MAAM,qBACL;AACpBE,EAAAA,UAAU,EAAE;AACVpC,IAAAA,eAAe,EAAE;AAAEqC,MAAAA,IAAI,EAAE;KAAU;AACnCxB,IAAAA,YAAY,EAAE;AAAEwB,MAAAA,IAAI,EAAE;KAAU;AAChChC,IAAAA,qBAAqB,EAAE;AAAEgC,MAAAA,IAAI,EAAE;AAAS;AAC1C;AACF,CACF,CAAC;;;;"}
@@ -1,133 +1,201 @@
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.$headings = this.$head ? Array.from(this.$head.querySelectorAll('th')) : [];
24
25
  this.createHeadingButtons();
25
26
  this.createStatusBox();
26
27
  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';
28
+ this.$head.addEventListener('click', this.onSortButtonClick.bind(this));
34
29
  }
35
30
  createHeadingButtons() {
36
- for (const heading of this.headings) {
37
- if (heading.hasAttribute('aria-sort')) {
38
- this.createHeadingButton(heading);
31
+ for (const $heading of this.$headings) {
32
+ if ($heading.hasAttribute('aria-sort')) {
33
+ this.createHeadingButton($heading);
39
34
  }
40
35
  }
41
36
  }
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);
37
+
38
+ /**
39
+ * @param {HTMLTableCellElement} $heading
40
+ */
41
+ createHeadingButton($heading) {
42
+ const index = this.$headings.indexOf($heading);
43
+ const $button = document.createElement('button');
44
+ $button.setAttribute('type', 'button');
45
+ $button.setAttribute('data-index', `${index}`);
46
+ $button.textContent = $heading.textContent;
47
+ $heading.textContent = '';
48
+ $heading.appendChild($button);
50
49
  }
51
50
  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);
51
+ this.$status = document.createElement('div');
52
+ this.$status.setAttribute('aria-atomic', 'true');
53
+ this.$status.setAttribute('aria-live', 'polite');
54
+ this.$status.setAttribute('class', 'govuk-visually-hidden');
55
+ this.$status.setAttribute('role', 'status');
56
+ this.$root.insertAdjacentElement('afterend', this.$status);
58
57
  }
59
58
  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')) {
59
+ var _$sortButton$getAttri;
60
+ const $rows = this.getTableRowsArray();
61
+ const $heading = this.$root.querySelector('th[aria-sort]');
62
+ const $sortButton = $heading == null ? void 0 : $heading.querySelector('button');
63
+ const sortDirection = $heading == null ? void 0 : $heading.getAttribute('aria-sort');
64
+ const columnNumber = Number.parseInt((_$sortButton$getAttri = $sortButton == null ? void 0 : $sortButton.getAttribute('data-index')) != null ? _$sortButton$getAttri : '0', 10);
65
+ if (!$heading || !$sortButton || !(sortDirection === 'ascending' || sortDirection === 'descending')) {
67
66
  return;
68
67
  }
69
- const sortedRows = this.sort(rows, columnNumber, sortDirection);
70
- this.addRows(sortedRows);
68
+ const $sortedRows = this.sort($rows, columnNumber, sortDirection);
69
+ this.addRows($sortedRows);
71
70
  }
71
+
72
+ /**
73
+ * @param {MouseEvent} event - Click event
74
+ */
72
75
  onSortButtonClick(event) {
73
- var _button$getAttribute;
74
- const button = event.target;
75
- if (!button || !(button instanceof HTMLButtonElement) || !button.parentElement) {
76
+ var _$button$getAttribute;
77
+ const $button = event.target;
78
+ if (!$button || !($button instanceof HTMLButtonElement) || !$button.parentElement) {
76
79
  return;
77
80
  }
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);
81
+ const $heading = $button.parentElement;
82
+ const sortDirection = $heading.getAttribute('aria-sort');
83
+ const columnNumber = Number.parseInt((_$button$getAttribute = $button == null ? void 0 : $button.getAttribute('data-index')) != null ? _$button$getAttribute : '0', 10);
81
84
  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);
85
+ const $rows = this.getTableRowsArray();
86
+ const $sortedRows = this.sort($rows, columnNumber, newSortDirection);
87
+ this.addRows($sortedRows);
85
88
  this.removeButtonStates();
86
- this.updateButtonState(button, newSortDirection);
89
+ this.updateButtonState($button, newSortDirection);
87
90
  }
88
- updateButtonState(button, direction) {
91
+
92
+ /**
93
+ * @param {HTMLButtonElement} $button
94
+ * @param {string} direction
95
+ */
96
+ updateButtonState($button, direction) {
89
97
  if (!(direction === 'ascending' || direction === 'descending')) {
90
98
  return;
91
99
  }
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;
100
+ $button.parentElement.setAttribute('aria-sort', direction);
101
+ let message = this.config.statusMessage;
102
+ message = message.replace(/%heading%/, $button.textContent);
103
+ message = message.replace(/%direction%/, this.config[`${direction}Text`]);
104
+ this.$status.textContent = message;
97
105
  }
98
106
  removeButtonStates() {
99
- for (const heading of this.headings) {
100
- heading.setAttribute('aria-sort', 'none');
107
+ for (const $heading of this.$headings) {
108
+ $heading.setAttribute('aria-sort', 'none');
101
109
  }
102
110
  }
103
- addRows(rows) {
104
- for (const row of rows) {
105
- this.body.append(row);
111
+
112
+ /**
113
+ * @param {HTMLTableRowElement[]} $rows
114
+ */
115
+ addRows($rows) {
116
+ for (const $row of $rows) {
117
+ this.$body.append($row);
106
118
  }
107
119
  }
108
120
  getTableRowsArray() {
109
- return Array.from(this.body.querySelectorAll('tr'));
121
+ return Array.from(this.$body.querySelectorAll('tr'));
110
122
  }
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)) {
123
+
124
+ /**
125
+ * @param {HTMLTableRowElement[]} $rows
126
+ * @param {number} columnNumber
127
+ * @param {string} sortDirection
128
+ */
129
+ sort($rows, columnNumber, sortDirection) {
130
+ return $rows.sort(($rowA, $rowB) => {
131
+ const $tdA = $rowA.querySelectorAll('td, th')[columnNumber];
132
+ const $tdB = $rowB.querySelectorAll('td, th')[columnNumber];
133
+ if (!$tdA || !$tdB || !($tdA instanceof HTMLElement) || !($tdB instanceof HTMLElement)) {
116
134
  return 0;
117
135
  }
118
- const valueA = sortDirection === 'ascending' ? this.getCellValue(tdA) : this.getCellValue(tdB);
119
- const valueB = sortDirection === 'ascending' ? this.getCellValue(tdB) : this.getCellValue(tdA);
136
+ const valueA = sortDirection === 'ascending' ? this.getCellValue($tdA) : this.getCellValue($tdB);
137
+ const valueB = sortDirection === 'ascending' ? this.getCellValue($tdB) : this.getCellValue($tdA);
120
138
  return !(typeof valueA === 'number' && typeof valueB === 'number') ? valueA.toString().localeCompare(valueB.toString()) : valueA - valueB;
121
139
  });
122
140
  }
123
- getCellValue(cell) {
124
- const val = cell.getAttribute('data-sort-value') || cell.innerHTML;
141
+
142
+ /**
143
+ * @param {HTMLElement} $cell
144
+ */
145
+ getCellValue($cell) {
146
+ const val = $cell.getAttribute('data-sort-value') || $cell.innerHTML;
125
147
  const valAsNumber = Number(val);
126
148
  return Number.isFinite(valAsNumber) ? valAsNumber // Exclude invalid numbers, infinity etc
127
149
  : val;
128
150
  }
151
+
152
+ /**
153
+ * Name for the component used when initialising using data-module attributes.
154
+ */
129
155
  }
130
156
 
157
+ /**
158
+ * Sortable table config
159
+ *
160
+ * @typedef {object} SortableTableConfig
161
+ * @property {string} [statusMessage] - Status message
162
+ * @property {string} [ascendingText] - Ascending text
163
+ * @property {string} [descendingText] - Descending text
164
+ */
165
+
166
+ /**
167
+ * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
168
+ */
169
+ SortableTable.moduleName = 'moj-sortable-table';
170
+ /**
171
+ * Sortable table config
172
+ *
173
+ * @type {SortableTableConfig}
174
+ */
175
+ SortableTable.defaults = Object.freeze({
176
+ statusMessage: 'Sort by %heading% (%direction%)',
177
+ ascendingText: 'ascending',
178
+ descendingText: 'descending'
179
+ });
180
+ /**
181
+ * Sortable table config schema
182
+ *
183
+ * @satisfies {Schema<SortableTableConfig>}
184
+ */
185
+ SortableTable.schema = Object.freeze(/** @type {const} */{
186
+ properties: {
187
+ statusMessage: {
188
+ type: 'string'
189
+ },
190
+ ascendingText: {
191
+ type: 'string'
192
+ },
193
+ descendingText: {
194
+ type: 'string'
195
+ }
196
+ }
197
+ });
198
+
131
199
  exports.SortableTable = SortableTable;
132
200
 
133
201
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"sortable-table.bundle.js","sources":["../../../../src/moj/components/sortable-table/sortable-table.mjs"],"sourcesContent":["export class SortableTable {\n constructor(params) {\n const table = params.table\n const head = table?.querySelector('thead')\n const body = table?.querySelector('tbody')\n\n if (!table || !(table instanceof HTMLElement) || !head || !body) {\n return this\n }\n\n this.table = table\n this.head = head\n this.body = body\n\n if (this.table.hasAttribute('data-moj-sortable-table-init')) {\n return this\n }\n\n this.table.setAttribute('data-moj-sortable-table-init', '')\n\n this.headings = this.head\n ? Array.from(this.head.querySelectorAll('th'))\n : []\n\n this.setupOptions(params)\n this.createHeadingButtons()\n this.createStatusBox()\n this.initialiseSortedColumn()\n\n this.head.addEventListener('click', this.onSortButtonClick.bind(this))\n }\n\n setupOptions(params) {\n params = params || {}\n this.statusMessage =\n params.statusMessage || 'Sort by %heading% (%direction%)'\n this.ascendingText = params.ascendingText || 'ascending'\n this.descendingText = params.descendingText || 'descending'\n }\n\n createHeadingButtons() {\n for (const heading of this.headings) {\n if (heading.hasAttribute('aria-sort')) {\n this.createHeadingButton(heading)\n }\n }\n }\n\n createHeadingButton(heading) {\n const index = this.headings.indexOf(heading)\n const button = document.createElement('button')\n\n button.setAttribute('type', 'button')\n button.setAttribute('data-index', `${index}`)\n button.textContent = heading.textContent\n\n heading.textContent = ''\n heading.appendChild(button)\n }\n\n createStatusBox() {\n this.status = document.createElement('div')\n\n this.status.setAttribute('aria-atomic', 'true')\n this.status.setAttribute('aria-live', 'polite')\n this.status.setAttribute('class', 'govuk-visually-hidden')\n this.status.setAttribute('role', 'status')\n\n this.table.insertAdjacentElement('afterend', this.status)\n }\n\n initialiseSortedColumn() {\n const rows = this.getTableRowsArray()\n\n const heading = this.table.querySelector('th[aria-sort]')\n const sortButton = heading?.querySelector('button')\n const sortDirection = heading?.getAttribute('aria-sort')\n const columnNumber = Number.parseInt(\n sortButton?.getAttribute('data-index') ?? '0',\n 10\n )\n\n if (\n !heading ||\n !sortButton ||\n !(sortDirection === 'ascending' || sortDirection === 'descending')\n ) {\n return\n }\n\n const sortedRows = this.sort(rows, columnNumber, sortDirection)\n this.addRows(sortedRows)\n }\n\n onSortButtonClick(event) {\n const button = event.target\n\n if (\n !button ||\n !(button instanceof HTMLButtonElement) ||\n !button.parentElement\n ) {\n return\n }\n\n const heading = button.parentElement\n const sortDirection = heading.getAttribute('aria-sort')\n const columnNumber = Number.parseInt(\n button?.getAttribute('data-index') ?? '0',\n 10\n )\n\n const newSortDirection =\n sortDirection === 'none' || sortDirection === 'descending'\n ? 'ascending'\n : 'descending'\n\n const rows = this.getTableRowsArray()\n const sortedRows = this.sort(rows, columnNumber, newSortDirection)\n\n this.addRows(sortedRows)\n this.removeButtonStates()\n this.updateButtonState(button, newSortDirection)\n }\n\n updateButtonState(button, direction) {\n if (!(direction === 'ascending' || direction === 'descending')) {\n return\n }\n\n button.parentElement.setAttribute('aria-sort', direction)\n let message = this.statusMessage\n message = message.replace(/%heading%/, button.textContent)\n message = message.replace(/%direction%/, this[`${direction}Text`])\n this.status.textContent = message\n }\n\n removeButtonStates() {\n for (const heading of this.headings) {\n heading.setAttribute('aria-sort', 'none')\n }\n }\n\n addRows(rows) {\n for (const row of rows) {\n this.body.append(row)\n }\n }\n\n getTableRowsArray() {\n return Array.from(this.body.querySelectorAll('tr'))\n }\n\n sort(rows, columnNumber, sortDirection) {\n return rows.sort((rowA, rowB) => {\n const tdA = rowA.querySelectorAll('td, th')[columnNumber]\n const tdB = rowB.querySelectorAll('td, th')[columnNumber]\n\n if (\n !tdA ||\n !tdB ||\n !(tdA instanceof HTMLElement) ||\n !(tdB instanceof HTMLElement)\n ) {\n return 0\n }\n\n const valueA =\n sortDirection === 'ascending'\n ? this.getCellValue(tdA)\n : this.getCellValue(tdB)\n\n const valueB =\n sortDirection === 'ascending'\n ? this.getCellValue(tdB)\n : this.getCellValue(tdA)\n\n return !(typeof valueA === 'number' && typeof valueB === 'number')\n ? valueA.toString().localeCompare(valueB.toString())\n : valueA - valueB\n })\n }\n\n getCellValue(cell) {\n const val = cell.getAttribute('data-sort-value') || cell.innerHTML\n const valAsNumber = Number(val)\n\n return Number.isFinite(valAsNumber)\n ? valAsNumber // Exclude invalid numbers, infinity etc\n : val\n }\n}\n"],"names":["SortableTable","constructor","params","table","head","querySelector","body","HTMLElement","hasAttribute","setAttribute","headings","Array","from","querySelectorAll","setupOptions","createHeadingButtons","createStatusBox","initialiseSortedColumn","addEventListener","onSortButtonClick","bind","statusMessage","ascendingText","descendingText","heading","createHeadingButton","index","indexOf","button","document","createElement","textContent","appendChild","status","insertAdjacentElement","_sortButton$getAttrib","rows","getTableRowsArray","sortButton","sortDirection","getAttribute","columnNumber","Number","parseInt","sortedRows","sort","addRows","event","_button$getAttribute","target","HTMLButtonElement","parentElement","newSortDirection","removeButtonStates","updateButtonState","direction","message","replace","row","append","rowA","rowB","tdA","tdB","valueA","getCellValue","valueB","toString","localeCompare","cell","val","innerHTML","valAsNumber","isFinite"],"mappings":"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"}
1
+ {"version":3,"file":"sortable-table.bundle.js","sources":["../../../../src/moj/components/sortable-table/sortable-table.mjs"],"sourcesContent":["import { ConfigurableComponent } from 'govuk-frontend'\n\n/**\n * @augments {ConfigurableComponent<SortableTableConfig>}\n */\nexport class SortableTable extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for sortable table\n * @param {SortableTableConfig} [config] - Sortable table config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n const $head = $root?.querySelector('thead')\n const $body = $root?.querySelector('tbody')\n\n if (!$head || !$body) {\n return this\n }\n\n this.$head = $head\n this.$body = $body\n\n this.$headings = this.$head\n ? Array.from(this.$head.querySelectorAll('th'))\n : []\n\n this.createHeadingButtons()\n this.createStatusBox()\n this.initialiseSortedColumn()\n\n this.$head.addEventListener('click', this.onSortButtonClick.bind(this))\n }\n\n createHeadingButtons() {\n for (const $heading of this.$headings) {\n if ($heading.hasAttribute('aria-sort')) {\n this.createHeadingButton($heading)\n }\n }\n }\n\n /**\n * @param {HTMLTableCellElement} $heading\n */\n createHeadingButton($heading) {\n const index = this.$headings.indexOf($heading)\n const $button = document.createElement('button')\n\n $button.setAttribute('type', 'button')\n $button.setAttribute('data-index', `${index}`)\n $button.textContent = $heading.textContent\n\n $heading.textContent = ''\n $heading.appendChild($button)\n }\n\n createStatusBox() {\n this.$status = document.createElement('div')\n\n this.$status.setAttribute('aria-atomic', 'true')\n this.$status.setAttribute('aria-live', 'polite')\n this.$status.setAttribute('class', 'govuk-visually-hidden')\n this.$status.setAttribute('role', 'status')\n\n this.$root.insertAdjacentElement('afterend', this.$status)\n }\n\n initialiseSortedColumn() {\n const $rows = this.getTableRowsArray()\n\n const $heading = this.$root.querySelector('th[aria-sort]')\n const $sortButton = $heading?.querySelector('button')\n const sortDirection = $heading?.getAttribute('aria-sort')\n\n const columnNumber = Number.parseInt(\n $sortButton?.getAttribute('data-index') ?? '0',\n 10\n )\n\n if (\n !$heading ||\n !$sortButton ||\n !(sortDirection === 'ascending' || sortDirection === 'descending')\n ) {\n return\n }\n\n const $sortedRows = this.sort($rows, columnNumber, sortDirection)\n this.addRows($sortedRows)\n }\n\n /**\n * @param {MouseEvent} event - Click event\n */\n onSortButtonClick(event) {\n const $button = event.target\n\n if (\n !$button ||\n !($button instanceof HTMLButtonElement) ||\n !$button.parentElement\n ) {\n return\n }\n\n const $heading = $button.parentElement\n const sortDirection = $heading.getAttribute('aria-sort')\n\n const columnNumber = Number.parseInt(\n $button?.getAttribute('data-index') ?? '0',\n 10\n )\n\n const newSortDirection =\n sortDirection === 'none' || sortDirection === 'descending'\n ? 'ascending'\n : 'descending'\n\n const $rows = this.getTableRowsArray()\n const $sortedRows = this.sort($rows, columnNumber, newSortDirection)\n\n this.addRows($sortedRows)\n this.removeButtonStates()\n this.updateButtonState($button, newSortDirection)\n }\n\n /**\n * @param {HTMLButtonElement} $button\n * @param {string} direction\n */\n updateButtonState($button, direction) {\n if (!(direction === 'ascending' || direction === 'descending')) {\n return\n }\n\n $button.parentElement.setAttribute('aria-sort', direction)\n let message = this.config.statusMessage\n message = message.replace(/%heading%/, $button.textContent)\n message = message.replace(/%direction%/, this.config[`${direction}Text`])\n this.$status.textContent = message\n }\n\n removeButtonStates() {\n for (const $heading of this.$headings) {\n $heading.setAttribute('aria-sort', 'none')\n }\n }\n\n /**\n * @param {HTMLTableRowElement[]} $rows\n */\n addRows($rows) {\n for (const $row of $rows) {\n this.$body.append($row)\n }\n }\n\n getTableRowsArray() {\n return Array.from(this.$body.querySelectorAll('tr'))\n }\n\n /**\n * @param {HTMLTableRowElement[]} $rows\n * @param {number} columnNumber\n * @param {string} sortDirection\n */\n sort($rows, columnNumber, sortDirection) {\n return $rows.sort(($rowA, $rowB) => {\n const $tdA = $rowA.querySelectorAll('td, th')[columnNumber]\n const $tdB = $rowB.querySelectorAll('td, th')[columnNumber]\n\n if (\n !$tdA ||\n !$tdB ||\n !($tdA instanceof HTMLElement) ||\n !($tdB instanceof HTMLElement)\n ) {\n return 0\n }\n\n const valueA =\n sortDirection === 'ascending'\n ? this.getCellValue($tdA)\n : this.getCellValue($tdB)\n\n const valueB =\n sortDirection === 'ascending'\n ? this.getCellValue($tdB)\n : this.getCellValue($tdA)\n\n return !(typeof valueA === 'number' && typeof valueB === 'number')\n ? valueA.toString().localeCompare(valueB.toString())\n : valueA - valueB\n })\n }\n\n /**\n * @param {HTMLElement} $cell\n */\n getCellValue($cell) {\n const val = $cell.getAttribute('data-sort-value') || $cell.innerHTML\n const valAsNumber = Number(val)\n\n return Number.isFinite(valAsNumber)\n ? valAsNumber // Exclude invalid numbers, infinity etc\n : val\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-sortable-table'\n\n /**\n * Sortable table config\n *\n * @type {SortableTableConfig}\n */\n static defaults = Object.freeze({\n statusMessage: 'Sort by %heading% (%direction%)',\n ascendingText: 'ascending',\n descendingText: 'descending'\n })\n\n /**\n * Sortable table config schema\n *\n * @satisfies {Schema<SortableTableConfig>}\n */\n static schema = Object.freeze(\n /** @type {const} */ ({\n properties: {\n statusMessage: { type: 'string' },\n ascendingText: { type: 'string' },\n descendingText: { type: 'string' }\n }\n })\n )\n}\n\n/**\n * Sortable table config\n *\n * @typedef {object} SortableTableConfig\n * @property {string} [statusMessage] - Status message\n * @property {string} [ascendingText] - Ascending text\n * @property {string} [descendingText] - Descending text\n */\n\n/**\n * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'\n */\n"],"names":["SortableTable","ConfigurableComponent","constructor","$root","config","$head","querySelector","$body","$headings","Array","from","querySelectorAll","createHeadingButtons","createStatusBox","initialiseSortedColumn","addEventListener","onSortButtonClick","bind","$heading","hasAttribute","createHeadingButton","index","indexOf","$button","document","createElement","setAttribute","textContent","appendChild","$status","insertAdjacentElement","_$sortButton$getAttri","$rows","getTableRowsArray","$sortButton","sortDirection","getAttribute","columnNumber","Number","parseInt","$sortedRows","sort","addRows","event","_$button$getAttribute","target","HTMLButtonElement","parentElement","newSortDirection","removeButtonStates","updateButtonState","direction","message","statusMessage","replace","$row","append","$rowA","$rowB","$tdA","$tdB","HTMLElement","valueA","getCellValue","valueB","toString","localeCompare","$cell","val","innerHTML","valAsNumber","isFinite","moduleName","defaults","Object","freeze","ascendingText","descendingText","schema","properties","type"],"mappings":"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"}