@ministryofjustice/frontend 5.1.0 → 5.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
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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"}
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 this.$caption = this.$root.querySelector('caption')\n\n 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\">\n<path d=\"M6.5625 15.5L11 6.63125L15.4375 15.5H6.5625Z\" fill=\"currentColor\"/>\n</svg>`\n 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\">\n<path d=\"M15.4375 7L11 15.8687L6.5625 7L15.4375 7Z\" fill=\"currentColor\"/>\n</svg>`\n 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\">\n<path d=\"M8.1875 9.5L10.9609 3.95703L13.7344 9.5H8.1875Z\" fill=\"currentColor\"/>\n<path d=\"M13.7344 12.0781L10.9609 17.6211L8.1875 12.0781H13.7344Z\" fill=\"currentColor\"/>\n</svg>`\n\n this.$headings = this.$head\n ? Array.from(this.$head.querySelectorAll('th'))\n : []\n\n this.createHeadingButtons()\n this.updateCaption()\n this.updateDirectionIndicators()\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(\n 'th[aria-sort=\"ascending\"], th[aria-sort=\"descending\"]'\n )\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 $target = /** @type {HTMLElement} */ (event.target)\n const $button = $target.closest('button')\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 this.updateDirectionIndicators()\n }\n\n updateCaption() {\n if (!this.$caption) {\n return\n }\n\n let assistiveText = this.$caption.querySelector('.govuk-visually-hidden')\n if (assistiveText) {\n return\n }\n\n assistiveText = document.createElement('span')\n assistiveText.classList.add('govuk-visually-hidden')\n assistiveText.textContent = ' (column headers with buttons are sortable).'\n\n this.$caption.appendChild(assistiveText)\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 updateDirectionIndicators() {\n for (const $heading of this.$headings) {\n const $button = /** @type {HTMLButtonElement} */ (\n $heading.querySelector('button')\n )\n if ($heading.hasAttribute('aria-sort') && $button) {\n const direction = $heading.getAttribute('aria-sort')\n $button.querySelector('svg')?.remove()\n\n switch (direction) {\n case 'ascending':\n $button.insertAdjacentHTML('beforeend', this.$upArrow)\n break\n case 'descending':\n $button.insertAdjacentHTML('beforeend', this.$downArrow)\n break\n default:\n $button.insertAdjacentHTML('beforeend', this.$upDownArrow)\n }\n }\n }\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","$caption","$upArrow","$downArrow","$upDownArrow","$headings","Array","from","querySelectorAll","createHeadingButtons","updateCaption","updateDirectionIndicators","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","target","closest","HTMLButtonElement","parentElement","newSortDirection","removeButtonStates","updateButtonState","assistiveText","classList","add","direction","message","statusMessage","replace","_$button$querySelecto","remove","insertAdjacentHTML","$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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"}
@@ -259,8 +259,21 @@ class SortableTable extends ConfigurableComponent {
259
259
  }
260
260
  this.$head = $head;
261
261
  this.$body = $body;
262
+ this.$caption = this.$root.querySelector('caption');
263
+ 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">
264
+ <path d="M6.5625 15.5L11 6.63125L15.4375 15.5H6.5625Z" fill="currentColor"/>
265
+ </svg>`;
266
+ 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">
267
+ <path d="M15.4375 7L11 15.8687L6.5625 7L15.4375 7Z" fill="currentColor"/>
268
+ </svg>`;
269
+ 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">
270
+ <path d="M8.1875 9.5L10.9609 3.95703L13.7344 9.5H8.1875Z" fill="currentColor"/>
271
+ <path d="M13.7344 12.0781L10.9609 17.6211L8.1875 12.0781H13.7344Z" fill="currentColor"/>
272
+ </svg>`;
262
273
  this.$headings = this.$head ? Array.from(this.$head.querySelectorAll('th')) : [];
263
274
  this.createHeadingButtons();
275
+ this.updateCaption();
276
+ this.updateDirectionIndicators();
264
277
  this.createStatusBox();
265
278
  this.initialiseSortedColumn();
266
279
  this.$head.addEventListener('click', this.onSortButtonClick.bind(this));
@@ -296,7 +309,7 @@ class SortableTable extends ConfigurableComponent {
296
309
  initialiseSortedColumn() {
297
310
  var _$sortButton$getAttri;
298
311
  const $rows = this.getTableRowsArray();
299
- const $heading = this.$root.querySelector('th[aria-sort]');
312
+ const $heading = this.$root.querySelector('th[aria-sort="ascending"], th[aria-sort="descending"]');
300
313
  const $sortButton = $heading == null ? void 0 : $heading.querySelector('button');
301
314
  const sortDirection = $heading == null ? void 0 : $heading.getAttribute('aria-sort');
302
315
  const columnNumber = Number.parseInt((_$sortButton$getAttri = $sortButton == null ? void 0 : $sortButton.getAttribute('data-index')) != null ? _$sortButton$getAttri : '0', 10);
@@ -312,7 +325,8 @@ class SortableTable extends ConfigurableComponent {
312
325
  */
313
326
  onSortButtonClick(event) {
314
327
  var _$button$getAttribute;
315
- const $button = event.target;
328
+ const $target = /** @type {HTMLElement} */event.target;
329
+ const $button = $target.closest('button');
316
330
  if (!$button || !($button instanceof HTMLButtonElement) || !$button.parentElement) {
317
331
  return;
318
332
  }
@@ -325,6 +339,20 @@ class SortableTable extends ConfigurableComponent {
325
339
  this.addRows($sortedRows);
326
340
  this.removeButtonStates();
327
341
  this.updateButtonState($button, newSortDirection);
342
+ this.updateDirectionIndicators();
343
+ }
344
+ updateCaption() {
345
+ if (!this.$caption) {
346
+ return;
347
+ }
348
+ let assistiveText = this.$caption.querySelector('.govuk-visually-hidden');
349
+ if (assistiveText) {
350
+ return;
351
+ }
352
+ assistiveText = document.createElement('span');
353
+ assistiveText.classList.add('govuk-visually-hidden');
354
+ assistiveText.textContent = ' (column headers with buttons are sortable).';
355
+ this.$caption.appendChild(assistiveText);
328
356
  }
329
357
 
330
358
  /**
@@ -341,6 +369,27 @@ class SortableTable extends ConfigurableComponent {
341
369
  message = message.replace(/%direction%/, this.config[`${direction}Text`]);
342
370
  this.$status.textContent = message;
343
371
  }
372
+ updateDirectionIndicators() {
373
+ for (const $heading of this.$headings) {
374
+ const $button = /** @type {HTMLButtonElement} */
375
+ $heading.querySelector('button');
376
+ if ($heading.hasAttribute('aria-sort') && $button) {
377
+ var _$button$querySelecto;
378
+ const direction = $heading.getAttribute('aria-sort');
379
+ (_$button$querySelecto = $button.querySelector('svg')) == null || _$button$querySelecto.remove();
380
+ switch (direction) {
381
+ case 'ascending':
382
+ $button.insertAdjacentHTML('beforeend', this.$upArrow);
383
+ break;
384
+ case 'descending':
385
+ $button.insertAdjacentHTML('beforeend', this.$downArrow);
386
+ break;
387
+ default:
388
+ $button.insertAdjacentHTML('beforeend', this.$upDownArrow);
389
+ }
390
+ }
391
+ }
392
+ }
344
393
  removeButtonStates() {
345
394
  for (const $heading of this.$headings) {
346
395
  $heading.setAttribute('aria-sort', 'none');
@@ -1 +1 @@
1
- {"version":3,"file":"sortable-table.bundle.mjs","sources":["../../../../node_modules/govuk-frontend/dist/govuk/common/index.mjs","../../../../node_modules/govuk-frontend/dist/govuk/errors/index.mjs","../../../../node_modules/govuk-frontend/dist/govuk/component.mjs","../../../../node_modules/govuk-frontend/dist/govuk/common/configuration.mjs","../../../../src/moj/components/sortable-table/sortable-table.mjs"],"sourcesContent":["function getFragmentFromUrl(url) {\n if (!url.includes('#')) {\n return undefined;\n }\n return url.split('#').pop();\n}\nfunction getBreakpoint(name) {\n const property = `--govuk-frontend-breakpoint-${name}`;\n const value = window.getComputedStyle(document.documentElement).getPropertyValue(property);\n return {\n property,\n value: value || undefined\n };\n}\nfunction setFocus($element, options = {}) {\n var _options$onBeforeFocu;\n const isFocusable = $element.getAttribute('tabindex');\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1');\n }\n function onFocus() {\n $element.addEventListener('blur', onBlur, {\n once: true\n });\n }\n function onBlur() {\n var _options$onBlur;\n (_options$onBlur = options.onBlur) == null || _options$onBlur.call($element);\n if (!isFocusable) {\n $element.removeAttribute('tabindex');\n }\n }\n $element.addEventListener('focus', onFocus, {\n once: true\n });\n (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);\n $element.focus();\n}\nfunction isInitialised($root, moduleName) {\n return $root instanceof HTMLElement && $root.hasAttribute(`data-${moduleName}-init`);\n}\n\n/**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * Some browsers will load and run our JavaScript but GOV.UK Frontend\n * won't be supported.\n *\n * @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support\n * @returns {boolean} Whether GOV.UK Frontend is supported on this page\n */\nfunction isSupported($scope = document.body) {\n if (!$scope) {\n return false;\n }\n return $scope.classList.contains('govuk-frontend-supported');\n}\nfunction isArray(option) {\n return Array.isArray(option);\n}\nfunction isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option);\n}\nfunction formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`;\n}\n/**\n * @typedef ComponentWithModuleName\n * @property {string} moduleName - Name of the component\n */\n/**\n * @import { ObjectNested } from './configuration.mjs'\n */\n\nexport { formatErrorMessage, getBreakpoint, getFragmentFromUrl, isInitialised, isObject, isSupported, setFocus };\n//# sourceMappingURL=index.mjs.map\n","import { formatErrorMessage } from '../common/index.mjs';\n\nclass GOVUKFrontendError extends Error {\n constructor(...args) {\n super(...args);\n this.name = 'GOVUKFrontendError';\n }\n}\nclass SupportError extends GOVUKFrontendError {\n /**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support\n */\n constructor($scope = document.body) {\n const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class=\"govuk-frontend-supported\">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';\n super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type=\"module\">`');\n this.name = 'SupportError';\n }\n}\nclass ConfigError extends GOVUKFrontendError {\n constructor(...args) {\n super(...args);\n this.name = 'ConfigError';\n }\n}\nclass ElementError extends GOVUKFrontendError {\n constructor(messageOrOptions) {\n let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';\n if (typeof messageOrOptions === 'object') {\n const {\n component,\n identifier,\n element,\n expectedType\n } = messageOrOptions;\n message = identifier;\n message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';\n message = formatErrorMessage(component, message);\n }\n super(message);\n this.name = 'ElementError';\n }\n}\nclass InitError extends GOVUKFrontendError {\n constructor(componentOrMessage) {\n const message = typeof componentOrMessage === 'string' ? componentOrMessage : formatErrorMessage(componentOrMessage, `Root element (\\`$root\\`) already initialised`);\n super(message);\n this.name = 'InitError';\n }\n}\n/**\n * @import { ComponentWithModuleName } from '../common/index.mjs'\n */\n\nexport { ConfigError, ElementError, GOVUKFrontendError, InitError, SupportError };\n//# sourceMappingURL=index.mjs.map\n","import { isInitialised, isSupported } from './common/index.mjs';\nimport { InitError, ElementError, SupportError } from './errors/index.mjs';\n\nclass Component {\n /**\n * Returns the root element of the component\n *\n * @protected\n * @returns {RootElementType} - the root element of component\n */\n get $root() {\n return this._$root;\n }\n constructor($root) {\n this._$root = void 0;\n const childConstructor = this.constructor;\n if (typeof childConstructor.moduleName !== 'string') {\n throw new InitError(`\\`moduleName\\` not defined in component`);\n }\n if (!($root instanceof childConstructor.elementType)) {\n throw new ElementError({\n element: $root,\n component: childConstructor,\n identifier: 'Root element (`$root`)',\n expectedType: childConstructor.elementType.name\n });\n } else {\n this._$root = $root;\n }\n childConstructor.checkSupport();\n this.checkInitialised();\n const moduleName = childConstructor.moduleName;\n this.$root.setAttribute(`data-${moduleName}-init`, '');\n }\n checkInitialised() {\n const constructor = this.constructor;\n const moduleName = constructor.moduleName;\n if (moduleName && isInitialised(this.$root, moduleName)) {\n throw new InitError(constructor);\n }\n }\n static checkSupport() {\n if (!isSupported()) {\n throw new SupportError();\n }\n }\n}\n\n/**\n * @typedef ChildClass\n * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component\n */\n\n/**\n * @typedef {typeof Component & ChildClass} ChildClassConstructor\n */\nComponent.elementType = HTMLElement;\n\nexport { Component };\n//# sourceMappingURL=component.mjs.map\n","import { Component } from '../component.mjs';\nimport { ConfigError } from '../errors/index.mjs';\nimport { isObject, formatErrorMessage } from './index.mjs';\n\nconst configOverride = Symbol.for('configOverride');\nclass ConfigurableComponent extends Component {\n [configOverride](param) {\n return {};\n }\n\n /**\n * Returns the root element of the component\n *\n * @protected\n * @returns {ConfigurationType} - the root element of component\n */\n get config() {\n return this._config;\n }\n constructor($root, config) {\n super($root);\n this._config = void 0;\n const childConstructor = this.constructor;\n if (!isObject(childConstructor.defaults)) {\n throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));\n }\n const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);\n this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);\n }\n}\nfunction normaliseString(value, property) {\n const trimmedValue = value ? value.trim() : '';\n let output;\n let outputType = property == null ? void 0 : property.type;\n if (!outputType) {\n if (['true', 'false'].includes(trimmedValue)) {\n outputType = 'boolean';\n }\n if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {\n outputType = 'number';\n }\n }\n switch (outputType) {\n case 'boolean':\n output = trimmedValue === 'true';\n break;\n case 'number':\n output = Number(trimmedValue);\n break;\n default:\n output = value;\n }\n return output;\n}\nfunction normaliseDataset(Component, dataset) {\n if (!isObject(Component.schema)) {\n throw new ConfigError(formatErrorMessage(Component, 'Config passed as parameter into constructor but no schema defined'));\n }\n const out = {};\n const entries = Object.entries(Component.schema.properties);\n for (const entry of entries) {\n const [namespace, property] = entry;\n const field = namespace.toString();\n if (field in dataset) {\n out[field] = normaliseString(dataset[field], property);\n }\n if ((property == null ? void 0 : property.type) === 'object') {\n out[field] = extractConfigByNamespace(Component.schema, dataset, namespace);\n }\n }\n return out;\n}\nfunction mergeConfigs(...configObjects) {\n const formattedConfigObject = {};\n for (const configObject of configObjects) {\n for (const key of Object.keys(configObject)) {\n const option = formattedConfigObject[key];\n const override = configObject[key];\n if (isObject(option) && isObject(override)) {\n formattedConfigObject[key] = mergeConfigs(option, override);\n } else {\n formattedConfigObject[key] = override;\n }\n }\n }\n return formattedConfigObject;\n}\nfunction validateConfig(schema, config) {\n const validationErrors = [];\n for (const [name, conditions] of Object.entries(schema)) {\n const errors = [];\n if (Array.isArray(conditions)) {\n for (const {\n required,\n errorMessage\n } of conditions) {\n if (!required.every(key => !!config[key])) {\n errors.push(errorMessage);\n }\n }\n if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {\n validationErrors.push(...errors);\n }\n }\n }\n return validationErrors;\n}\nfunction extractConfigByNamespace(schema, dataset, namespace) {\n const property = schema.properties[namespace];\n if ((property == null ? void 0 : property.type) !== 'object') {\n return;\n }\n const newObject = {\n [namespace]: {}\n };\n for (const [key, value] of Object.entries(dataset)) {\n let current = newObject;\n const keyParts = key.split('.');\n for (const [index, name] of keyParts.entries()) {\n if (isObject(current)) {\n if (index < keyParts.length - 1) {\n if (!isObject(current[name])) {\n current[name] = {};\n }\n current = current[name];\n } else if (key !== namespace) {\n current[name] = normaliseString(value);\n }\n }\n }\n }\n return newObject[namespace];\n}\n/**\n * Schema for component config\n *\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @typedef {object} Schema\n * @property {Record<keyof ConfigurationType, SchemaProperty | undefined>} properties - Schema properties\n * @property {SchemaCondition<ConfigurationType>[]} [anyOf] - List of schema conditions\n */\n/**\n * Schema property for component config\n *\n * @typedef {object} SchemaProperty\n * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type\n */\n/**\n * Schema condition for component config\n *\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @typedef {object} SchemaCondition\n * @property {(keyof ConfigurationType)[]} required - List of required config fields\n * @property {string} errorMessage - Error message when required config fields not provided\n */\n/**\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]\n * @typedef ChildClass\n * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component\n * @property {Schema<ConfigurationType>} [schema] - The schema of the component configuration\n * @property {ConfigurationType} [defaults] - The default values of the configuration of the component\n */\n/**\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]\n * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>\n */\n\nexport { ConfigurableComponent, configOverride, extractConfigByNamespace, mergeConfigs, normaliseDataset, normaliseString, validateConfig };\n//# sourceMappingURL=configuration.mjs.map\n","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":["isInitialised","$root","moduleName","HTMLElement","hasAttribute","isSupported","$scope","document","body","classList","contains","isArray","option","Array","isObject","formatErrorMessage","Component","message","GOVUKFrontendError","Error","constructor","args","name","SupportError","supportMessage","HTMLScriptElement","prototype","ConfigError","ElementError","messageOrOptions","component","identifier","element","expectedType","InitError","componentOrMessage","_$root","childConstructor","elementType","checkSupport","checkInitialised","setAttribute","configOverride","Symbol","for","ConfigurableComponent","param","config","_config","defaults","datasetConfig","normaliseDataset","dataset","mergeConfigs","normaliseString","value","property","trimmedValue","trim","output","outputType","type","includes","length","isFinite","Number","schema","out","entries","Object","properties","entry","namespace","field","toString","extractConfigByNamespace","configObjects","formattedConfigObject","configObject","key","keys","override","newObject","current","keyParts","split","index","SortableTable","$head","querySelector","$body","$headings","from","querySelectorAll","createHeadingButtons","createStatusBox","initialiseSortedColumn","addEventListener","onSortButtonClick","bind","$heading","createHeadingButton","indexOf","$button","createElement","textContent","appendChild","$status","insertAdjacentElement","_$sortButton$getAttri","$rows","getTableRowsArray","$sortButton","sortDirection","getAttribute","columnNumber","parseInt","$sortedRows","sort","addRows","event","_$button$getAttribute","target","HTMLButtonElement","parentElement","newSortDirection","removeButtonStates","updateButtonState","direction","statusMessage","replace","$row","append","$rowA","$rowB","$tdA","$tdB","valueA","getCellValue","valueB","localeCompare","$cell","val","innerHTML","valAsNumber","freeze","ascendingText","descendingText"],"mappings":"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","x_google_ignoreList":[0,1,2,3]}
1
+ {"version":3,"file":"sortable-table.bundle.mjs","sources":["../../../../node_modules/govuk-frontend/dist/govuk/common/index.mjs","../../../../node_modules/govuk-frontend/dist/govuk/errors/index.mjs","../../../../node_modules/govuk-frontend/dist/govuk/component.mjs","../../../../node_modules/govuk-frontend/dist/govuk/common/configuration.mjs","../../../../src/moj/components/sortable-table/sortable-table.mjs"],"sourcesContent":["function getFragmentFromUrl(url) {\n if (!url.includes('#')) {\n return undefined;\n }\n return url.split('#').pop();\n}\nfunction getBreakpoint(name) {\n const property = `--govuk-frontend-breakpoint-${name}`;\n const value = window.getComputedStyle(document.documentElement).getPropertyValue(property);\n return {\n property,\n value: value || undefined\n };\n}\nfunction setFocus($element, options = {}) {\n var _options$onBeforeFocu;\n const isFocusable = $element.getAttribute('tabindex');\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1');\n }\n function onFocus() {\n $element.addEventListener('blur', onBlur, {\n once: true\n });\n }\n function onBlur() {\n var _options$onBlur;\n (_options$onBlur = options.onBlur) == null || _options$onBlur.call($element);\n if (!isFocusable) {\n $element.removeAttribute('tabindex');\n }\n }\n $element.addEventListener('focus', onFocus, {\n once: true\n });\n (_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);\n $element.focus();\n}\nfunction isInitialised($root, moduleName) {\n return $root instanceof HTMLElement && $root.hasAttribute(`data-${moduleName}-init`);\n}\n\n/**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * Some browsers will load and run our JavaScript but GOV.UK Frontend\n * won't be supported.\n *\n * @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support\n * @returns {boolean} Whether GOV.UK Frontend is supported on this page\n */\nfunction isSupported($scope = document.body) {\n if (!$scope) {\n return false;\n }\n return $scope.classList.contains('govuk-frontend-supported');\n}\nfunction isArray(option) {\n return Array.isArray(option);\n}\nfunction isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option);\n}\nfunction formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`;\n}\n/**\n * @typedef ComponentWithModuleName\n * @property {string} moduleName - Name of the component\n */\n/**\n * @import { ObjectNested } from './configuration.mjs'\n */\n\nexport { formatErrorMessage, getBreakpoint, getFragmentFromUrl, isInitialised, isObject, isSupported, setFocus };\n//# sourceMappingURL=index.mjs.map\n","import { formatErrorMessage } from '../common/index.mjs';\n\nclass GOVUKFrontendError extends Error {\n constructor(...args) {\n super(...args);\n this.name = 'GOVUKFrontendError';\n }\n}\nclass SupportError extends GOVUKFrontendError {\n /**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support\n */\n constructor($scope = document.body) {\n const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class=\"govuk-frontend-supported\">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';\n super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type=\"module\">`');\n this.name = 'SupportError';\n }\n}\nclass ConfigError extends GOVUKFrontendError {\n constructor(...args) {\n super(...args);\n this.name = 'ConfigError';\n }\n}\nclass ElementError extends GOVUKFrontendError {\n constructor(messageOrOptions) {\n let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';\n if (typeof messageOrOptions === 'object') {\n const {\n component,\n identifier,\n element,\n expectedType\n } = messageOrOptions;\n message = identifier;\n message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';\n message = formatErrorMessage(component, message);\n }\n super(message);\n this.name = 'ElementError';\n }\n}\nclass InitError extends GOVUKFrontendError {\n constructor(componentOrMessage) {\n const message = typeof componentOrMessage === 'string' ? componentOrMessage : formatErrorMessage(componentOrMessage, `Root element (\\`$root\\`) already initialised`);\n super(message);\n this.name = 'InitError';\n }\n}\n/**\n * @import { ComponentWithModuleName } from '../common/index.mjs'\n */\n\nexport { ConfigError, ElementError, GOVUKFrontendError, InitError, SupportError };\n//# sourceMappingURL=index.mjs.map\n","import { isInitialised, isSupported } from './common/index.mjs';\nimport { InitError, ElementError, SupportError } from './errors/index.mjs';\n\nclass Component {\n /**\n * Returns the root element of the component\n *\n * @protected\n * @returns {RootElementType} - the root element of component\n */\n get $root() {\n return this._$root;\n }\n constructor($root) {\n this._$root = void 0;\n const childConstructor = this.constructor;\n if (typeof childConstructor.moduleName !== 'string') {\n throw new InitError(`\\`moduleName\\` not defined in component`);\n }\n if (!($root instanceof childConstructor.elementType)) {\n throw new ElementError({\n element: $root,\n component: childConstructor,\n identifier: 'Root element (`$root`)',\n expectedType: childConstructor.elementType.name\n });\n } else {\n this._$root = $root;\n }\n childConstructor.checkSupport();\n this.checkInitialised();\n const moduleName = childConstructor.moduleName;\n this.$root.setAttribute(`data-${moduleName}-init`, '');\n }\n checkInitialised() {\n const constructor = this.constructor;\n const moduleName = constructor.moduleName;\n if (moduleName && isInitialised(this.$root, moduleName)) {\n throw new InitError(constructor);\n }\n }\n static checkSupport() {\n if (!isSupported()) {\n throw new SupportError();\n }\n }\n}\n\n/**\n * @typedef ChildClass\n * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component\n */\n\n/**\n * @typedef {typeof Component & ChildClass} ChildClassConstructor\n */\nComponent.elementType = HTMLElement;\n\nexport { Component };\n//# sourceMappingURL=component.mjs.map\n","import { Component } from '../component.mjs';\nimport { ConfigError } from '../errors/index.mjs';\nimport { isObject, formatErrorMessage } from './index.mjs';\n\nconst configOverride = Symbol.for('configOverride');\nclass ConfigurableComponent extends Component {\n [configOverride](param) {\n return {};\n }\n\n /**\n * Returns the root element of the component\n *\n * @protected\n * @returns {ConfigurationType} - the root element of component\n */\n get config() {\n return this._config;\n }\n constructor($root, config) {\n super($root);\n this._config = void 0;\n const childConstructor = this.constructor;\n if (!isObject(childConstructor.defaults)) {\n throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));\n }\n const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);\n this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);\n }\n}\nfunction normaliseString(value, property) {\n const trimmedValue = value ? value.trim() : '';\n let output;\n let outputType = property == null ? void 0 : property.type;\n if (!outputType) {\n if (['true', 'false'].includes(trimmedValue)) {\n outputType = 'boolean';\n }\n if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {\n outputType = 'number';\n }\n }\n switch (outputType) {\n case 'boolean':\n output = trimmedValue === 'true';\n break;\n case 'number':\n output = Number(trimmedValue);\n break;\n default:\n output = value;\n }\n return output;\n}\nfunction normaliseDataset(Component, dataset) {\n if (!isObject(Component.schema)) {\n throw new ConfigError(formatErrorMessage(Component, 'Config passed as parameter into constructor but no schema defined'));\n }\n const out = {};\n const entries = Object.entries(Component.schema.properties);\n for (const entry of entries) {\n const [namespace, property] = entry;\n const field = namespace.toString();\n if (field in dataset) {\n out[field] = normaliseString(dataset[field], property);\n }\n if ((property == null ? void 0 : property.type) === 'object') {\n out[field] = extractConfigByNamespace(Component.schema, dataset, namespace);\n }\n }\n return out;\n}\nfunction mergeConfigs(...configObjects) {\n const formattedConfigObject = {};\n for (const configObject of configObjects) {\n for (const key of Object.keys(configObject)) {\n const option = formattedConfigObject[key];\n const override = configObject[key];\n if (isObject(option) && isObject(override)) {\n formattedConfigObject[key] = mergeConfigs(option, override);\n } else {\n formattedConfigObject[key] = override;\n }\n }\n }\n return formattedConfigObject;\n}\nfunction validateConfig(schema, config) {\n const validationErrors = [];\n for (const [name, conditions] of Object.entries(schema)) {\n const errors = [];\n if (Array.isArray(conditions)) {\n for (const {\n required,\n errorMessage\n } of conditions) {\n if (!required.every(key => !!config[key])) {\n errors.push(errorMessage);\n }\n }\n if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {\n validationErrors.push(...errors);\n }\n }\n }\n return validationErrors;\n}\nfunction extractConfigByNamespace(schema, dataset, namespace) {\n const property = schema.properties[namespace];\n if ((property == null ? void 0 : property.type) !== 'object') {\n return;\n }\n const newObject = {\n [namespace]: {}\n };\n for (const [key, value] of Object.entries(dataset)) {\n let current = newObject;\n const keyParts = key.split('.');\n for (const [index, name] of keyParts.entries()) {\n if (isObject(current)) {\n if (index < keyParts.length - 1) {\n if (!isObject(current[name])) {\n current[name] = {};\n }\n current = current[name];\n } else if (key !== namespace) {\n current[name] = normaliseString(value);\n }\n }\n }\n }\n return newObject[namespace];\n}\n/**\n * Schema for component config\n *\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @typedef {object} Schema\n * @property {Record<keyof ConfigurationType, SchemaProperty | undefined>} properties - Schema properties\n * @property {SchemaCondition<ConfigurationType>[]} [anyOf] - List of schema conditions\n */\n/**\n * Schema property for component config\n *\n * @typedef {object} SchemaProperty\n * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type\n */\n/**\n * Schema condition for component config\n *\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @typedef {object} SchemaCondition\n * @property {(keyof ConfigurationType)[]} required - List of required config fields\n * @property {string} errorMessage - Error message when required config fields not provided\n */\n/**\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]\n * @typedef ChildClass\n * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component\n * @property {Schema<ConfigurationType>} [schema] - The schema of the component configuration\n * @property {ConfigurationType} [defaults] - The default values of the configuration of the component\n */\n/**\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]\n * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>\n */\n\nexport { ConfigurableComponent, configOverride, extractConfigByNamespace, mergeConfigs, normaliseDataset, normaliseString, validateConfig };\n//# sourceMappingURL=configuration.mjs.map\n","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 this.$caption = this.$root.querySelector('caption')\n\n 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\">\n<path d=\"M6.5625 15.5L11 6.63125L15.4375 15.5H6.5625Z\" fill=\"currentColor\"/>\n</svg>`\n 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\">\n<path d=\"M15.4375 7L11 15.8687L6.5625 7L15.4375 7Z\" fill=\"currentColor\"/>\n</svg>`\n 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\">\n<path d=\"M8.1875 9.5L10.9609 3.95703L13.7344 9.5H8.1875Z\" fill=\"currentColor\"/>\n<path d=\"M13.7344 12.0781L10.9609 17.6211L8.1875 12.0781H13.7344Z\" fill=\"currentColor\"/>\n</svg>`\n\n this.$headings = this.$head\n ? Array.from(this.$head.querySelectorAll('th'))\n : []\n\n this.createHeadingButtons()\n this.updateCaption()\n this.updateDirectionIndicators()\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(\n 'th[aria-sort=\"ascending\"], th[aria-sort=\"descending\"]'\n )\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 $target = /** @type {HTMLElement} */ (event.target)\n const $button = $target.closest('button')\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 this.updateDirectionIndicators()\n }\n\n updateCaption() {\n if (!this.$caption) {\n return\n }\n\n let assistiveText = this.$caption.querySelector('.govuk-visually-hidden')\n if (assistiveText) {\n return\n }\n\n assistiveText = document.createElement('span')\n assistiveText.classList.add('govuk-visually-hidden')\n assistiveText.textContent = ' (column headers with buttons are sortable).'\n\n this.$caption.appendChild(assistiveText)\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 updateDirectionIndicators() {\n for (const $heading of this.$headings) {\n const $button = /** @type {HTMLButtonElement} */ (\n $heading.querySelector('button')\n )\n if ($heading.hasAttribute('aria-sort') && $button) {\n const direction = $heading.getAttribute('aria-sort')\n $button.querySelector('svg')?.remove()\n\n switch (direction) {\n case 'ascending':\n $button.insertAdjacentHTML('beforeend', this.$upArrow)\n break\n case 'descending':\n $button.insertAdjacentHTML('beforeend', this.$downArrow)\n break\n default:\n $button.insertAdjacentHTML('beforeend', this.$upDownArrow)\n }\n }\n }\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":["isInitialised","$root","moduleName","HTMLElement","hasAttribute","isSupported","$scope","document","body","classList","contains","isArray","option","Array","isObject","formatErrorMessage","Component","message","GOVUKFrontendError","Error","constructor","args","name","SupportError","supportMessage","HTMLScriptElement","prototype","ConfigError","ElementError","messageOrOptions","component","identifier","element","expectedType","InitError","componentOrMessage","_$root","childConstructor","elementType","checkSupport","checkInitialised","setAttribute","configOverride","Symbol","for","ConfigurableComponent","param","config","_config","defaults","datasetConfig","normaliseDataset","dataset","mergeConfigs","normaliseString","value","property","trimmedValue","trim","output","outputType","type","includes","length","isFinite","Number","schema","out","entries","Object","properties","entry","namespace","field","toString","extractConfigByNamespace","configObjects","formattedConfigObject","configObject","key","keys","override","newObject","current","keyParts","split","index","SortableTable","$head","querySelector","$body","$caption","$upArrow","$downArrow","$upDownArrow","$headings","from","querySelectorAll","createHeadingButtons","updateCaption","updateDirectionIndicators","createStatusBox","initialiseSortedColumn","addEventListener","onSortButtonClick","bind","$heading","createHeadingButton","indexOf","$button","createElement","textContent","appendChild","$status","insertAdjacentElement","_$sortButton$getAttri","$rows","getTableRowsArray","$sortButton","sortDirection","getAttribute","columnNumber","parseInt","$sortedRows","sort","addRows","event","_$button$getAttribute","$target","target","closest","HTMLButtonElement","parentElement","newSortDirection","removeButtonStates","updateButtonState","assistiveText","add","direction","statusMessage","replace","_$button$querySelecto","remove","insertAdjacentHTML","$row","append","$rowA","$rowB","$tdA","$tdB","valueA","getCellValue","valueB","localeCompare","$cell","val","innerHTML","valAsNumber","freeze","ascendingText","descendingText"],"mappings":"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","x_google_ignoreList":[0,1,2,3]}
@@ -17,8 +17,21 @@ class SortableTable extends ConfigurableComponent {
17
17
  }
18
18
  this.$head = $head;
19
19
  this.$body = $body;
20
+ this.$caption = this.$root.querySelector('caption');
21
+ 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">
22
+ <path d="M6.5625 15.5L11 6.63125L15.4375 15.5H6.5625Z" fill="currentColor"/>
23
+ </svg>`;
24
+ 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">
25
+ <path d="M15.4375 7L11 15.8687L6.5625 7L15.4375 7Z" fill="currentColor"/>
26
+ </svg>`;
27
+ 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">
28
+ <path d="M8.1875 9.5L10.9609 3.95703L13.7344 9.5H8.1875Z" fill="currentColor"/>
29
+ <path d="M13.7344 12.0781L10.9609 17.6211L8.1875 12.0781H13.7344Z" fill="currentColor"/>
30
+ </svg>`;
20
31
  this.$headings = this.$head ? Array.from(this.$head.querySelectorAll('th')) : [];
21
32
  this.createHeadingButtons();
33
+ this.updateCaption();
34
+ this.updateDirectionIndicators();
22
35
  this.createStatusBox();
23
36
  this.initialiseSortedColumn();
24
37
  this.$head.addEventListener('click', this.onSortButtonClick.bind(this));
@@ -54,7 +67,7 @@ class SortableTable extends ConfigurableComponent {
54
67
  initialiseSortedColumn() {
55
68
  var _$sortButton$getAttri;
56
69
  const $rows = this.getTableRowsArray();
57
- const $heading = this.$root.querySelector('th[aria-sort]');
70
+ const $heading = this.$root.querySelector('th[aria-sort="ascending"], th[aria-sort="descending"]');
58
71
  const $sortButton = $heading == null ? void 0 : $heading.querySelector('button');
59
72
  const sortDirection = $heading == null ? void 0 : $heading.getAttribute('aria-sort');
60
73
  const columnNumber = Number.parseInt((_$sortButton$getAttri = $sortButton == null ? void 0 : $sortButton.getAttribute('data-index')) != null ? _$sortButton$getAttri : '0', 10);
@@ -70,7 +83,8 @@ class SortableTable extends ConfigurableComponent {
70
83
  */
71
84
  onSortButtonClick(event) {
72
85
  var _$button$getAttribute;
73
- const $button = event.target;
86
+ const $target = /** @type {HTMLElement} */event.target;
87
+ const $button = $target.closest('button');
74
88
  if (!$button || !($button instanceof HTMLButtonElement) || !$button.parentElement) {
75
89
  return;
76
90
  }
@@ -83,6 +97,20 @@ class SortableTable extends ConfigurableComponent {
83
97
  this.addRows($sortedRows);
84
98
  this.removeButtonStates();
85
99
  this.updateButtonState($button, newSortDirection);
100
+ this.updateDirectionIndicators();
101
+ }
102
+ updateCaption() {
103
+ if (!this.$caption) {
104
+ return;
105
+ }
106
+ let assistiveText = this.$caption.querySelector('.govuk-visually-hidden');
107
+ if (assistiveText) {
108
+ return;
109
+ }
110
+ assistiveText = document.createElement('span');
111
+ assistiveText.classList.add('govuk-visually-hidden');
112
+ assistiveText.textContent = ' (column headers with buttons are sortable).';
113
+ this.$caption.appendChild(assistiveText);
86
114
  }
87
115
 
88
116
  /**
@@ -99,6 +127,27 @@ class SortableTable extends ConfigurableComponent {
99
127
  message = message.replace(/%direction%/, this.config[`${direction}Text`]);
100
128
  this.$status.textContent = message;
101
129
  }
130
+ updateDirectionIndicators() {
131
+ for (const $heading of this.$headings) {
132
+ const $button = /** @type {HTMLButtonElement} */
133
+ $heading.querySelector('button');
134
+ if ($heading.hasAttribute('aria-sort') && $button) {
135
+ var _$button$querySelecto;
136
+ const direction = $heading.getAttribute('aria-sort');
137
+ (_$button$querySelecto = $button.querySelector('svg')) == null || _$button$querySelecto.remove();
138
+ switch (direction) {
139
+ case 'ascending':
140
+ $button.insertAdjacentHTML('beforeend', this.$upArrow);
141
+ break;
142
+ case 'descending':
143
+ $button.insertAdjacentHTML('beforeend', this.$downArrow);
144
+ break;
145
+ default:
146
+ $button.insertAdjacentHTML('beforeend', this.$upDownArrow);
147
+ }
148
+ }
149
+ }
150
+ }
102
151
  removeButtonStates() {
103
152
  for (const $heading of this.$headings) {
104
153
  $heading.setAttribute('aria-sort', 'none');
@@ -1 +1 @@
1
- {"version":3,"file":"sortable-table.mjs","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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"}
1
+ {"version":3,"file":"sortable-table.mjs","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 this.$caption = this.$root.querySelector('caption')\n\n 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\">\n<path d=\"M6.5625 15.5L11 6.63125L15.4375 15.5H6.5625Z\" fill=\"currentColor\"/>\n</svg>`\n 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\">\n<path d=\"M15.4375 7L11 15.8687L6.5625 7L15.4375 7Z\" fill=\"currentColor\"/>\n</svg>`\n 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\">\n<path d=\"M8.1875 9.5L10.9609 3.95703L13.7344 9.5H8.1875Z\" fill=\"currentColor\"/>\n<path d=\"M13.7344 12.0781L10.9609 17.6211L8.1875 12.0781H13.7344Z\" fill=\"currentColor\"/>\n</svg>`\n\n this.$headings = this.$head\n ? Array.from(this.$head.querySelectorAll('th'))\n : []\n\n this.createHeadingButtons()\n this.updateCaption()\n this.updateDirectionIndicators()\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(\n 'th[aria-sort=\"ascending\"], th[aria-sort=\"descending\"]'\n )\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 $target = /** @type {HTMLElement} */ (event.target)\n const $button = $target.closest('button')\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 this.updateDirectionIndicators()\n }\n\n updateCaption() {\n if (!this.$caption) {\n return\n }\n\n let assistiveText = this.$caption.querySelector('.govuk-visually-hidden')\n if (assistiveText) {\n return\n }\n\n assistiveText = document.createElement('span')\n assistiveText.classList.add('govuk-visually-hidden')\n assistiveText.textContent = ' (column headers with buttons are sortable).'\n\n this.$caption.appendChild(assistiveText)\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 updateDirectionIndicators() {\n for (const $heading of this.$headings) {\n const $button = /** @type {HTMLButtonElement} */ (\n $heading.querySelector('button')\n )\n if ($heading.hasAttribute('aria-sort') && $button) {\n const direction = $heading.getAttribute('aria-sort')\n $button.querySelector('svg')?.remove()\n\n switch (direction) {\n case 'ascending':\n $button.insertAdjacentHTML('beforeend', this.$upArrow)\n break\n case 'descending':\n $button.insertAdjacentHTML('beforeend', this.$downArrow)\n break\n default:\n $button.insertAdjacentHTML('beforeend', this.$upDownArrow)\n }\n }\n }\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","$caption","$upArrow","$downArrow","$upDownArrow","$headings","Array","from","querySelectorAll","createHeadingButtons","updateCaption","updateDirectionIndicators","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","target","closest","HTMLButtonElement","parentElement","newSortDirection","removeButtonStates","updateButtonState","assistiveText","classList","add","direction","message","statusMessage","replace","_$button$querySelecto","remove","insertAdjacentHTML","$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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"}
@@ -1,7 +1,7 @@
1
1
  :root {
2
2
  // This variable is automatically overwritten during builds and releases.
3
3
  // It doesn't need to be updated manually.
4
- --moj-frontend-version: "5.1.0";
4
+ --moj-frontend-version: "5.1.2";
5
5
  }
6
6
 
7
7
  /*# sourceMappingURL=_moj-frontend-properties.scss.map */