@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 +1 @@
1
- {"version":3,"file":"alert.bundle.mjs","sources":["../../../../src/moj/helpers.mjs","../../../../src/moj/components/alert/alert.mjs"],"sourcesContent":["export function removeAttributeValue(el, attr, value) {\n let re, m\n if (el.getAttribute(attr)) {\n if (el.getAttribute(attr) === value) {\n el.removeAttribute(attr)\n } else {\n re = new RegExp(`(^|\\\\s)${value}(\\\\s|$)`)\n m = el.getAttribute(attr).match(re)\n if (m && m.length === 3) {\n el.setAttribute(\n attr,\n el.getAttribute(attr).replace(re, m[1] && m[2] ? ' ' : '')\n )\n }\n }\n }\n}\n\nexport function addAttributeValue(el, attr, value) {\n let re\n if (!el.getAttribute(attr)) {\n el.setAttribute(attr, value)\n } else {\n re = new RegExp(`(^|\\\\s)${value}(\\\\s|$)`)\n if (!re.test(el.getAttribute(attr))) {\n el.setAttribute(attr, `${el.getAttribute(attr)} ${value}`)\n }\n }\n}\n\nexport function dragAndDropSupported() {\n const div = document.createElement('div')\n return typeof div.ondrop !== 'undefined'\n}\n\nexport function formDataSupported() {\n return typeof FormData === 'function'\n}\n\nexport function fileApiSupported() {\n const input = document.createElement('input')\n input.type = 'file'\n return typeof input.files !== 'undefined'\n}\n\n/**\n * Find an elements next sibling\n *\n * Utility function to find an elements next sibling matching the provided\n * selector.\n *\n * @param {Element | null} $element - Element to find siblings for\n * @param {string} [selector] - selector for required sibling\n */\nexport function getNextSibling($element, selector) {\n if (!$element || !($element instanceof HTMLElement)) {\n return\n }\n\n // Get the next sibling element\n let $sibling = $element.nextElementSibling\n\n // If there's no selector, return the first sibling\n if (!selector) return $sibling\n\n // If the sibling matches our selector, use it\n // If not, jump to the next sibling and continue the loop\n while ($sibling) {\n if ($sibling.matches(selector)) return $sibling\n $sibling = $sibling.nextElementSibling\n }\n}\n\n/**\n * Find an elements preceding sibling\n *\n * Utility function to find an elements previous sibling matching the provided\n * selector.\n *\n * @param {Element | null} $element - Element to find siblings for\n * @param {string} [selector] - selector for required sibling\n */\nexport function getPreviousSibling($element, selector) {\n if (!$element || !($element instanceof HTMLElement)) {\n return\n }\n\n // Get the previous sibling element\n let $sibling = $element.previousElementSibling\n\n // If there's no selector, return the first sibling\n if (!selector) return $sibling\n\n // If the sibling matches our selector, use it\n // If not, jump to the next sibling and continue the loop\n while ($sibling) {\n if ($sibling.matches(selector)) return $sibling\n $sibling = $sibling.previousElementSibling\n }\n}\n\n/**\n * @param {Element | null} $element\n * @param {string} [selector]\n */\nexport function findNearestMatchingElement($element, selector) {\n // If no element or selector is provided, return\n if (!$element || !($element instanceof HTMLElement) || !selector) {\n return\n }\n\n // Start with the current element\n let $currentElement = $element\n\n while ($currentElement) {\n // First check the current element\n if ($currentElement.matches(selector)) {\n return $currentElement\n }\n\n // Check all previous siblings\n let $sibling = $currentElement.previousElementSibling\n while ($sibling) {\n // Check if the sibling itself is a heading\n if ($sibling.matches(selector)) {\n return $sibling\n }\n $sibling = $sibling.previousElementSibling\n }\n\n // If no match found in siblings, move up to parent\n $currentElement = $currentElement.parentElement\n }\n}\n\n/**\n * Move focus to element\n *\n * Sets tabindex to -1 to make the element programmatically focusable,\n * but removes it on blur as the element doesn't need to be focused again.\n *\n * @param {HTMLElement} $element - HTML element\n * @param {object} [options] - Handler options\n * @param {function(this: HTMLElement): void} [options.onBeforeFocus] - Callback before focus\n * @param {function(this: HTMLElement): void} [options.onBlur] - Callback on blur\n */\nexport function setFocus($element, options = {}) {\n const isFocusable = $element.getAttribute('tabindex')\n\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1')\n }\n\n /**\n * Handle element focus\n */\n function onFocus() {\n $element.addEventListener('blur', onBlur, { once: true })\n }\n\n /**\n * Handle element blur\n */\n function onBlur() {\n if (options.onBlur) {\n options.onBlur.call($element)\n }\n\n if (!isFocusable) {\n $element.removeAttribute('tabindex')\n }\n }\n\n // Add listener to reset element on blur, after focus\n $element.addEventListener('focus', onFocus, { once: true })\n\n // Focus element\n if (options.onBeforeFocus) {\n options.onBeforeFocus.call($element)\n }\n $element.focus()\n}\n","import {\n findNearestMatchingElement,\n getPreviousSibling,\n setFocus\n} from '../../helpers.mjs'\n\nexport class Alert {\n /**\n * @param {Element | null} $module - HTML element to use for alert\n * @param {AlertConfig} [config] - Alert config\n */\n constructor($module, config = {}) {\n if (!$module || !($module instanceof HTMLElement)) {\n return this\n }\n\n const schema = Object.freeze({\n properties: {\n dismissible: { type: 'boolean' },\n dismissText: { type: 'string' },\n disableAutoFocus: { type: 'boolean' },\n focusOnDismissSelector: { type: 'string' }\n }\n })\n\n const defaults = {\n dismissible: false,\n dismissText: 'Dismiss',\n disableAutoFocus: false\n }\n\n // data attributes override JS config, which overrides defaults\n this.config = this.mergeConfigs(\n defaults,\n config,\n this.parseDataset(schema, $module.dataset)\n )\n\n this.$module = $module\n\n /**\n * Focus the alert\n *\n * If `role=\"alert\"` is set, focus the element to help some assistive\n * technologies prioritise announcing it.\n *\n * You can turn off the auto-focus functionality by setting\n * `data-disable-auto-focus=\"true\"` in the component HTML. You might wish to\n * do this based on user research findings, or to avoid a clash with another\n * element which should be focused when the page loads.\n */\n if (\n this.$module.getAttribute('role') === 'alert' &&\n !this.config.disableAutoFocus\n ) {\n setFocus(this.$module)\n }\n\n this.$dismissButton = this.$module.querySelector('.moj-alert__dismiss')\n\n if (this.config.dismissible && this.$dismissButton) {\n this.$dismissButton.innerHTML = this.config.dismissText\n this.$dismissButton.removeAttribute('hidden')\n\n this.$module.addEventListener('click', (event) => {\n if (\n event.target instanceof Node &&\n this.$dismissButton.contains(event.target)\n ) {\n this.dimiss()\n }\n })\n }\n }\n\n /**\n * Handle dismissing the alert\n */\n dimiss() {\n let $elementToRecieveFocus\n\n // If a selector has been provided, attempt to find that element\n if (this.config.focusOnDismissSelector) {\n $elementToRecieveFocus = document.querySelector(\n this.config.focusOnDismissSelector\n )\n }\n\n // Is the next sibling another alert\n if (!$elementToRecieveFocus) {\n const $nextSibling = this.$module.nextElementSibling\n if ($nextSibling && $nextSibling.matches('.moj-alert')) {\n $elementToRecieveFocus = $nextSibling\n }\n }\n\n // Else try to find any preceding sibling alert or heading\n if (!$elementToRecieveFocus) {\n $elementToRecieveFocus = getPreviousSibling(\n this.$module,\n '.moj-alert, h1, h2, h3, h4, h5, h6'\n )\n }\n\n // Else find the closest ancestor heading, or fallback to main, or last resort\n // use the body element\n if (!$elementToRecieveFocus) {\n $elementToRecieveFocus = findNearestMatchingElement(\n this.$module,\n 'h1, h2, h3, h4, h5, h6, main, body'\n )\n }\n\n // If we have an element, place focus on it\n if ($elementToRecieveFocus instanceof HTMLElement) {\n setFocus($elementToRecieveFocus)\n }\n\n // Remove the alert\n this.$module.remove()\n }\n\n /**\n * Normalise string\n *\n * 'If it looks like a duck, and it quacks like a duck…' 🦆\n *\n * If the passed value looks like a boolean or a number, convert it to a boolean\n * or number.\n *\n * Designed to be used to convert config passed via data attributes (which are\n * always strings) into something sensible.\n *\n * @internal\n * @param {DOMStringMap[string]} value - The value to normalise\n * @param {SchemaProperty} [property] - Component schema property\n * @returns {string | boolean | number | undefined} Normalised data\n */\n normaliseString(value, property) {\n const trimmedValue = value ? value.trim() : ''\n\n let output\n let outputType\n if (property && property.type) {\n outputType = property.type\n }\n\n // No schema type set? Determine automatically\n if (!outputType) {\n if (['true', 'false'].includes(trimmedValue)) {\n outputType = 'boolean'\n }\n\n // Empty / whitespace-only strings are considered finite so we need to check\n // the length of the trimmed string as well\n if (trimmedValue.length > 0 && Number.isFinite(Number(trimmedValue))) {\n outputType = 'number'\n }\n }\n\n switch (outputType) {\n case 'boolean':\n output = trimmedValue === 'true'\n break\n\n case 'number':\n output = Number(trimmedValue)\n break\n\n default:\n output = value\n }\n\n return output\n }\n\n /**\n * Parse dataset\n *\n * Loop over an object and normalise each value using {@link normaliseString},\n * optionally expanding nested `i18n.field`\n *\n * @param {Schema} schema - component schema\n * @param {DOMStringMap} dataset - HTML element dataset\n * @returns {object} Normalised dataset\n */\n parseDataset(schema, dataset) {\n const parsed = {}\n\n for (const [field, property] of Object.entries(schema.properties)) {\n if (field in dataset) {\n if (dataset[field]) {\n parsed[field] = this.normaliseString(dataset[field], property)\n }\n }\n }\n\n return parsed\n }\n\n /**\n * Config merging function\n *\n * Takes any number of objects and combines them together, with\n * greatest priority on the LAST item passed in.\n *\n * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge\n * @returns {{ [key: string]: unknown }} A merged config object\n */\n mergeConfigs(...configObjects) {\n const formattedConfigObject = {}\n\n // Loop through each of the passed objects\n for (const configObject of configObjects) {\n for (const key of Object.keys(configObject)) {\n const option = formattedConfigObject[key]\n const override = configObject[key]\n\n // Push their keys one-by-one into formattedConfigObject. Any duplicate\n // keys with object values will be merged, otherwise the new value will\n // override the existing value.\n if (typeof option === 'object' && typeof override === 'object') {\n // @ts-expect-error Index signature for type 'string' is missing\n formattedConfigObject[key] = this.mergeConfigs(option, override)\n } else {\n formattedConfigObject[key] = override\n }\n }\n }\n\n return formattedConfigObject\n }\n}\n\n/**\n * @typedef {object} AlertConfig\n * @property {boolean} [dismissible=false] - Can the alert be dismissed by the user\n * @property {string} [dismissText=Dismiss] - the label text for the dismiss button\n * @property {boolean} [disableAutoFocus=false] - whether the alert will be autofocused\n * @property {string} [focusOnDismissSelector] - CSS Selector for element to be focused on dismiss\n */\n"],"names":["getPreviousSibling","$element","selector","HTMLElement","$sibling","previousElementSibling","matches","findNearestMatchingElement","$currentElement","parentElement","setFocus","options","isFocusable","getAttribute","setAttribute","onFocus","addEventListener","onBlur","once","call","removeAttribute","onBeforeFocus","focus","Alert","constructor","$module","config","schema","Object","freeze","properties","dismissible","type","dismissText","disableAutoFocus","focusOnDismissSelector","defaults","mergeConfigs","parseDataset","dataset","$dismissButton","querySelector","innerHTML","event","target","Node","contains","dimiss","$elementToRecieveFocus","document","$nextSibling","nextElementSibling","remove","normaliseString","value","property","trimmedValue","trim","output","outputType","includes","length","Number","isFinite","parsed","field","entries","configObjects","formattedConfigObject","configObject","key","keys","option","override"],"mappings":"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"}
1
+ {"version":3,"file":"alert.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/common/index.mjs","../../../../src/moj/helpers.mjs","../../../../src/moj/components/alert/alert.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","/**\n * GOV.UK Frontend helpers\n *\n * @todo Import from GOV.UK Frontend\n */\n\n/**\n * Move focus to element\n *\n * Sets tabindex to -1 to make the element programmatically focusable,\n * but removes it on blur as the element doesn't need to be focused again.\n *\n * @template {HTMLElement} FocusElement\n * @param {FocusElement} $element - HTML element\n * @param {object} [options] - Handler options\n * @param {function(this: FocusElement): void} [options.onBeforeFocus] - Callback before focus\n * @param {function(this: FocusElement): void} [options.onBlur] - Callback on blur\n */\nexport function setFocus($element, options = {}) {\n const isFocusable = $element.getAttribute('tabindex')\n\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1')\n }\n\n /**\n * Handle element focus\n */\n function onFocus() {\n $element.addEventListener('blur', onBlur, { once: true })\n }\n\n /**\n * Handle element blur\n */\n function onBlur() {\n options.onBlur?.call($element)\n\n if (!isFocusable) {\n $element.removeAttribute('tabindex')\n }\n }\n\n // Add listener to reset element on blur, after focus\n $element.addEventListener('focus', onFocus, { once: true })\n\n // Focus element\n options.onBeforeFocus?.call($element)\n $element.focus()\n}\n","/**\n * @param {Element} $element - Element to remove attribute value from\n * @param {string} attr - Attribute name\n * @param {string} value - Attribute value\n */\nexport function removeAttributeValue($element, attr, value) {\n let re, m\n if ($element.getAttribute(attr)) {\n if ($element.getAttribute(attr) === value) {\n $element.removeAttribute(attr)\n } else {\n re = new RegExp(`(^|\\\\s)${value}(\\\\s|$)`)\n m = $element.getAttribute(attr).match(re)\n if (m && m.length === 3) {\n $element.setAttribute(\n attr,\n $element.getAttribute(attr).replace(re, m[1] && m[2] ? ' ' : '')\n )\n }\n }\n }\n}\n\n/**\n * @param {Element} $element - Element to add attribute value to\n * @param {string} attr - Attribute name\n * @param {string} value - Attribute value\n */\nexport function addAttributeValue($element, attr, value) {\n let re\n if (!$element.getAttribute(attr)) {\n $element.setAttribute(attr, value)\n } else {\n re = new RegExp(`(^|\\\\s)${value}(\\\\s|$)`)\n if (!re.test($element.getAttribute(attr))) {\n $element.setAttribute(attr, `${$element.getAttribute(attr)} ${value}`)\n }\n }\n}\n\n/**\n * Find an elements next sibling\n *\n * Utility function to find an elements next sibling matching the provided\n * selector.\n *\n * @param {Element | null} $element - Element to find siblings for\n * @param {string} [selector] - selector for required sibling\n */\nexport function getNextSibling($element, selector) {\n if (!$element || !($element instanceof HTMLElement)) {\n return\n }\n\n // Get the next sibling element\n let $sibling = $element.nextElementSibling\n\n // If there's no selector, return the first sibling\n if (!selector) return $sibling\n\n // If the sibling matches our selector, use it\n // If not, jump to the next sibling and continue the loop\n while ($sibling) {\n if ($sibling.matches(selector)) return $sibling\n $sibling = $sibling.nextElementSibling\n }\n}\n\n/**\n * Find an elements preceding sibling\n *\n * Utility function to find an elements previous sibling matching the provided\n * selector.\n *\n * @param {Element | null} $element - Element to find siblings for\n * @param {string} [selector] - selector for required sibling\n */\nexport function getPreviousSibling($element, selector) {\n if (!$element || !($element instanceof HTMLElement)) {\n return\n }\n\n // Get the previous sibling element\n let $sibling = $element.previousElementSibling\n\n // If there's no selector, return the first sibling\n if (!selector) return $sibling\n\n // If the sibling matches our selector, use it\n // If not, jump to the next sibling and continue the loop\n while ($sibling) {\n if ($sibling.matches(selector)) return $sibling\n $sibling = $sibling.previousElementSibling\n }\n}\n\n/**\n * @param {Element | null} $element\n * @param {string} [selector]\n */\nexport function findNearestMatchingElement($element, selector) {\n // If no element or selector is provided, return\n if (!$element || !($element instanceof HTMLElement) || !selector) {\n return\n }\n\n // Start with the current element\n let $currentElement = $element\n\n while ($currentElement) {\n // First check the current element\n if ($currentElement.matches(selector)) {\n return $currentElement\n }\n\n // Check all previous siblings\n let $sibling = $currentElement.previousElementSibling\n while ($sibling) {\n // Check if the sibling itself is a heading\n if ($sibling.matches(selector)) {\n return $sibling\n }\n $sibling = $sibling.previousElementSibling\n }\n\n // If no match found in siblings, move up to parent\n $currentElement = $currentElement.parentElement\n }\n}\n","import { ConfigurableComponent } from 'govuk-frontend'\n\nimport { setFocus } from '../../common/index.mjs'\nimport {\n findNearestMatchingElement,\n getPreviousSibling\n} from '../../helpers.mjs'\n\n/**\n * @augments {ConfigurableComponent<AlertConfig>}\n */\nexport class Alert extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for alert\n * @param {AlertConfig} [config] - Alert config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n /**\n * Focus the alert\n *\n * If `role=\"alert\"` is set, focus the element to help some assistive\n * technologies prioritise announcing it.\n *\n * You can turn off the auto-focus functionality by setting\n * `data-disable-auto-focus=\"true\"` in the component HTML. You might wish to\n * do this based on user research findings, or to avoid a clash with another\n * element which should be focused when the page loads.\n */\n if (\n this.$root.getAttribute('role') === 'alert' &&\n !this.config.disableAutoFocus\n ) {\n setFocus(this.$root)\n }\n\n this.$dismissButton = this.$root.querySelector('.moj-alert__dismiss')\n\n if (this.config.dismissible && this.$dismissButton) {\n this.$dismissButton.innerHTML = this.config.dismissText\n this.$dismissButton.removeAttribute('hidden')\n\n this.$root.addEventListener('click', (event) => {\n if (\n event.target instanceof Node &&\n this.$dismissButton.contains(event.target)\n ) {\n this.dimiss()\n }\n })\n }\n }\n\n /**\n * Handle dismissing the alert\n */\n dimiss() {\n let $elementToRecieveFocus\n\n // If a selector has been provided, attempt to find that element\n if (this.config.focusOnDismissSelector) {\n $elementToRecieveFocus = document.querySelector(\n this.config.focusOnDismissSelector\n )\n }\n\n // Is the next sibling another alert\n if (!$elementToRecieveFocus) {\n const $nextSibling = this.$root.nextElementSibling\n if ($nextSibling && $nextSibling.matches('.moj-alert')) {\n $elementToRecieveFocus = $nextSibling\n }\n }\n\n // Else try to find any preceding sibling alert or heading\n if (!$elementToRecieveFocus) {\n $elementToRecieveFocus = getPreviousSibling(\n this.$root,\n '.moj-alert, h1, h2, h3, h4, h5, h6'\n )\n }\n\n // Else find the closest ancestor heading, or fallback to main, or last resort\n // use the body element\n if (!$elementToRecieveFocus) {\n $elementToRecieveFocus = findNearestMatchingElement(\n this.$root,\n 'h1, h2, h3, h4, h5, h6, main, body'\n )\n }\n\n // If we have an element, place focus on it\n if ($elementToRecieveFocus instanceof HTMLElement) {\n setFocus($elementToRecieveFocus)\n }\n\n // Remove the alert\n this.$root.remove()\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-alert'\n\n /**\n * Alert default config\n *\n * @type {AlertConfig}\n */\n static defaults = Object.freeze({\n dismissible: false,\n dismissText: 'Dismiss',\n disableAutoFocus: false\n })\n\n /**\n * Alert config schema\n *\n * @satisfies {Schema<AlertConfig>}\n */\n static schema = Object.freeze(\n /** @type {const} */ ({\n properties: {\n dismissible: { type: 'boolean' },\n dismissText: { type: 'string' },\n disableAutoFocus: { type: 'boolean' },\n focusOnDismissSelector: { type: 'string' }\n }\n })\n )\n}\n\n/**\n * @typedef {object} AlertConfig\n * @property {boolean} [dismissible=false] - Can the alert be dismissed by the user\n * @property {string} [dismissText=Dismiss] - the label text for the dismiss button\n * @property {boolean} [disableAutoFocus=false] - whether the alert will be autofocused\n * @property {string} [focusOnDismissSelector] - CSS Selector for element to be focused on dismiss\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","setFocus","$element","options","_options$onBeforeFocu","isFocusable","getAttribute","onFocus","addEventListener","onBlur","once","_options$onBlur","call","removeAttribute","onBeforeFocus","focus","getPreviousSibling","selector","$sibling","previousElementSibling","matches","findNearestMatchingElement","$currentElement","parentElement","Alert","disableAutoFocus","$dismissButton","querySelector","dismissible","innerHTML","dismissText","event","target","Node","dimiss","$elementToRecieveFocus","focusOnDismissSelector","$nextSibling","nextElementSibling","remove","freeze"],"mappings":"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","x_google_ignoreList":[0,1,2,3]}
@@ -1,39 +1,17 @@
1
- import { setFocus, getPreviousSibling, findNearestMatchingElement } from '../../helpers.mjs';
1
+ import { ConfigurableComponent } from 'govuk-frontend';
2
+ import { setFocus } from '../../common/index.mjs';
3
+ import { getPreviousSibling, findNearestMatchingElement } from '../../helpers.mjs';
2
4
 
3
- class Alert {
5
+ /**
6
+ * @augments {ConfigurableComponent<AlertConfig>}
7
+ */
8
+ class Alert extends ConfigurableComponent {
4
9
  /**
5
- * @param {Element | null} $module - HTML element to use for alert
10
+ * @param {Element | null} $root - HTML element to use for alert
6
11
  * @param {AlertConfig} [config] - Alert config
7
12
  */
8
- constructor($module, config = {}) {
9
- if (!$module || !($module instanceof HTMLElement)) {
10
- return this;
11
- }
12
- const schema = Object.freeze({
13
- properties: {
14
- dismissible: {
15
- type: 'boolean'
16
- },
17
- dismissText: {
18
- type: 'string'
19
- },
20
- disableAutoFocus: {
21
- type: 'boolean'
22
- },
23
- focusOnDismissSelector: {
24
- type: 'string'
25
- }
26
- }
27
- });
28
- const defaults = {
29
- dismissible: false,
30
- dismissText: 'Dismiss',
31
- disableAutoFocus: false
32
- };
33
-
34
- // data attributes override JS config, which overrides defaults
35
- this.config = this.mergeConfigs(defaults, config, this.parseDataset(schema, $module.dataset));
36
- this.$module = $module;
13
+ constructor($root, config = {}) {
14
+ super($root, config);
37
15
 
38
16
  /**
39
17
  * Focus the alert
@@ -46,14 +24,14 @@ class Alert {
46
24
  * do this based on user research findings, or to avoid a clash with another
47
25
  * element which should be focused when the page loads.
48
26
  */
49
- if (this.$module.getAttribute('role') === 'alert' && !this.config.disableAutoFocus) {
50
- setFocus(this.$module);
27
+ if (this.$root.getAttribute('role') === 'alert' && !this.config.disableAutoFocus) {
28
+ setFocus(this.$root);
51
29
  }
52
- this.$dismissButton = this.$module.querySelector('.moj-alert__dismiss');
30
+ this.$dismissButton = this.$root.querySelector('.moj-alert__dismiss');
53
31
  if (this.config.dismissible && this.$dismissButton) {
54
32
  this.$dismissButton.innerHTML = this.config.dismissText;
55
33
  this.$dismissButton.removeAttribute('hidden');
56
- this.$module.addEventListener('click', event => {
34
+ this.$root.addEventListener('click', event => {
57
35
  if (event.target instanceof Node && this.$dismissButton.contains(event.target)) {
58
36
  this.dimiss();
59
37
  }
@@ -74,7 +52,7 @@ class Alert {
74
52
 
75
53
  // Is the next sibling another alert
76
54
  if (!$elementToRecieveFocus) {
77
- const $nextSibling = this.$module.nextElementSibling;
55
+ const $nextSibling = this.$root.nextElementSibling;
78
56
  if ($nextSibling && $nextSibling.matches('.moj-alert')) {
79
57
  $elementToRecieveFocus = $nextSibling;
80
58
  }
@@ -82,13 +60,13 @@ class Alert {
82
60
 
83
61
  // Else try to find any preceding sibling alert or heading
84
62
  if (!$elementToRecieveFocus) {
85
- $elementToRecieveFocus = getPreviousSibling(this.$module, '.moj-alert, h1, h2, h3, h4, h5, h6');
63
+ $elementToRecieveFocus = getPreviousSibling(this.$root, '.moj-alert, h1, h2, h3, h4, h5, h6');
86
64
  }
87
65
 
88
66
  // Else find the closest ancestor heading, or fallback to main, or last resort
89
67
  // use the body element
90
68
  if (!$elementToRecieveFocus) {
91
- $elementToRecieveFocus = findNearestMatchingElement(this.$module, 'h1, h2, h3, h4, h5, h6, main, body');
69
+ $elementToRecieveFocus = findNearestMatchingElement(this.$root, 'h1, h2, h3, h4, h5, h6, main, body');
92
70
  }
93
71
 
94
72
  // If we have an element, place focus on it
@@ -97,111 +75,12 @@ class Alert {
97
75
  }
98
76
 
99
77
  // Remove the alert
100
- this.$module.remove();
101
- }
102
-
103
- /**
104
- * Normalise string
105
- *
106
- * 'If it looks like a duck, and it quacks like a duck…' 🦆
107
- *
108
- * If the passed value looks like a boolean or a number, convert it to a boolean
109
- * or number.
110
- *
111
- * Designed to be used to convert config passed via data attributes (which are
112
- * always strings) into something sensible.
113
- *
114
- * @internal
115
- * @param {DOMStringMap[string]} value - The value to normalise
116
- * @param {SchemaProperty} [property] - Component schema property
117
- * @returns {string | boolean | number | undefined} Normalised data
118
- */
119
- normaliseString(value, property) {
120
- const trimmedValue = value ? value.trim() : '';
121
- let output;
122
- let outputType;
123
- if (property && property.type) {
124
- outputType = property.type;
125
- }
126
-
127
- // No schema type set? Determine automatically
128
- if (!outputType) {
129
- if (['true', 'false'].includes(trimmedValue)) {
130
- outputType = 'boolean';
131
- }
132
-
133
- // Empty / whitespace-only strings are considered finite so we need to check
134
- // the length of the trimmed string as well
135
- if (trimmedValue.length > 0 && Number.isFinite(Number(trimmedValue))) {
136
- outputType = 'number';
137
- }
138
- }
139
- switch (outputType) {
140
- case 'boolean':
141
- output = trimmedValue === 'true';
142
- break;
143
- case 'number':
144
- output = Number(trimmedValue);
145
- break;
146
- default:
147
- output = value;
148
- }
149
- return output;
78
+ this.$root.remove();
150
79
  }
151
80
 
152
81
  /**
153
- * Parse dataset
154
- *
155
- * Loop over an object and normalise each value using {@link normaliseString},
156
- * optionally expanding nested `i18n.field`
157
- *
158
- * @param {Schema} schema - component schema
159
- * @param {DOMStringMap} dataset - HTML element dataset
160
- * @returns {object} Normalised dataset
82
+ * Name for the component used when initialising using data-module attributes.
161
83
  */
162
- parseDataset(schema, dataset) {
163
- const parsed = {};
164
- for (const [field, property] of Object.entries(schema.properties)) {
165
- if (field in dataset) {
166
- if (dataset[field]) {
167
- parsed[field] = this.normaliseString(dataset[field], property);
168
- }
169
- }
170
- }
171
- return parsed;
172
- }
173
-
174
- /**
175
- * Config merging function
176
- *
177
- * Takes any number of objects and combines them together, with
178
- * greatest priority on the LAST item passed in.
179
- *
180
- * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge
181
- * @returns {{ [key: string]: unknown }} A merged config object
182
- */
183
- mergeConfigs(...configObjects) {
184
- const formattedConfigObject = {};
185
-
186
- // Loop through each of the passed objects
187
- for (const configObject of configObjects) {
188
- for (const key of Object.keys(configObject)) {
189
- const option = formattedConfigObject[key];
190
- const override = configObject[key];
191
-
192
- // Push their keys one-by-one into formattedConfigObject. Any duplicate
193
- // keys with object values will be merged, otherwise the new value will
194
- // override the existing value.
195
- if (typeof option === 'object' && typeof override === 'object') {
196
- // @ts-expect-error Index signature for type 'string' is missing
197
- formattedConfigObject[key] = this.mergeConfigs(option, override);
198
- } else {
199
- formattedConfigObject[key] = override;
200
- }
201
- }
202
- }
203
- return formattedConfigObject;
204
- }
205
84
  }
206
85
 
207
86
  /**
@@ -212,5 +91,41 @@ class Alert {
212
91
  * @property {string} [focusOnDismissSelector] - CSS Selector for element to be focused on dismiss
213
92
  */
214
93
 
94
+ /**
95
+ * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
96
+ */
97
+ Alert.moduleName = 'moj-alert';
98
+ /**
99
+ * Alert default config
100
+ *
101
+ * @type {AlertConfig}
102
+ */
103
+ Alert.defaults = Object.freeze({
104
+ dismissible: false,
105
+ dismissText: 'Dismiss',
106
+ disableAutoFocus: false
107
+ });
108
+ /**
109
+ * Alert config schema
110
+ *
111
+ * @satisfies {Schema<AlertConfig>}
112
+ */
113
+ Alert.schema = Object.freeze(/** @type {const} */{
114
+ properties: {
115
+ dismissible: {
116
+ type: 'boolean'
117
+ },
118
+ dismissText: {
119
+ type: 'string'
120
+ },
121
+ disableAutoFocus: {
122
+ type: 'boolean'
123
+ },
124
+ focusOnDismissSelector: {
125
+ type: 'string'
126
+ }
127
+ }
128
+ });
129
+
215
130
  export { Alert };
216
131
  //# sourceMappingURL=alert.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"alert.mjs","sources":["../../../../src/moj/components/alert/alert.mjs"],"sourcesContent":["import {\n findNearestMatchingElement,\n getPreviousSibling,\n setFocus\n} from '../../helpers.mjs'\n\nexport class Alert {\n /**\n * @param {Element | null} $module - HTML element to use for alert\n * @param {AlertConfig} [config] - Alert config\n */\n constructor($module, config = {}) {\n if (!$module || !($module instanceof HTMLElement)) {\n return this\n }\n\n const schema = Object.freeze({\n properties: {\n dismissible: { type: 'boolean' },\n dismissText: { type: 'string' },\n disableAutoFocus: { type: 'boolean' },\n focusOnDismissSelector: { type: 'string' }\n }\n })\n\n const defaults = {\n dismissible: false,\n dismissText: 'Dismiss',\n disableAutoFocus: false\n }\n\n // data attributes override JS config, which overrides defaults\n this.config = this.mergeConfigs(\n defaults,\n config,\n this.parseDataset(schema, $module.dataset)\n )\n\n this.$module = $module\n\n /**\n * Focus the alert\n *\n * If `role=\"alert\"` is set, focus the element to help some assistive\n * technologies prioritise announcing it.\n *\n * You can turn off the auto-focus functionality by setting\n * `data-disable-auto-focus=\"true\"` in the component HTML. You might wish to\n * do this based on user research findings, or to avoid a clash with another\n * element which should be focused when the page loads.\n */\n if (\n this.$module.getAttribute('role') === 'alert' &&\n !this.config.disableAutoFocus\n ) {\n setFocus(this.$module)\n }\n\n this.$dismissButton = this.$module.querySelector('.moj-alert__dismiss')\n\n if (this.config.dismissible && this.$dismissButton) {\n this.$dismissButton.innerHTML = this.config.dismissText\n this.$dismissButton.removeAttribute('hidden')\n\n this.$module.addEventListener('click', (event) => {\n if (\n event.target instanceof Node &&\n this.$dismissButton.contains(event.target)\n ) {\n this.dimiss()\n }\n })\n }\n }\n\n /**\n * Handle dismissing the alert\n */\n dimiss() {\n let $elementToRecieveFocus\n\n // If a selector has been provided, attempt to find that element\n if (this.config.focusOnDismissSelector) {\n $elementToRecieveFocus = document.querySelector(\n this.config.focusOnDismissSelector\n )\n }\n\n // Is the next sibling another alert\n if (!$elementToRecieveFocus) {\n const $nextSibling = this.$module.nextElementSibling\n if ($nextSibling && $nextSibling.matches('.moj-alert')) {\n $elementToRecieveFocus = $nextSibling\n }\n }\n\n // Else try to find any preceding sibling alert or heading\n if (!$elementToRecieveFocus) {\n $elementToRecieveFocus = getPreviousSibling(\n this.$module,\n '.moj-alert, h1, h2, h3, h4, h5, h6'\n )\n }\n\n // Else find the closest ancestor heading, or fallback to main, or last resort\n // use the body element\n if (!$elementToRecieveFocus) {\n $elementToRecieveFocus = findNearestMatchingElement(\n this.$module,\n 'h1, h2, h3, h4, h5, h6, main, body'\n )\n }\n\n // If we have an element, place focus on it\n if ($elementToRecieveFocus instanceof HTMLElement) {\n setFocus($elementToRecieveFocus)\n }\n\n // Remove the alert\n this.$module.remove()\n }\n\n /**\n * Normalise string\n *\n * 'If it looks like a duck, and it quacks like a duck…' 🦆\n *\n * If the passed value looks like a boolean or a number, convert it to a boolean\n * or number.\n *\n * Designed to be used to convert config passed via data attributes (which are\n * always strings) into something sensible.\n *\n * @internal\n * @param {DOMStringMap[string]} value - The value to normalise\n * @param {SchemaProperty} [property] - Component schema property\n * @returns {string | boolean | number | undefined} Normalised data\n */\n normaliseString(value, property) {\n const trimmedValue = value ? value.trim() : ''\n\n let output\n let outputType\n if (property && property.type) {\n outputType = property.type\n }\n\n // No schema type set? Determine automatically\n if (!outputType) {\n if (['true', 'false'].includes(trimmedValue)) {\n outputType = 'boolean'\n }\n\n // Empty / whitespace-only strings are considered finite so we need to check\n // the length of the trimmed string as well\n if (trimmedValue.length > 0 && Number.isFinite(Number(trimmedValue))) {\n outputType = 'number'\n }\n }\n\n switch (outputType) {\n case 'boolean':\n output = trimmedValue === 'true'\n break\n\n case 'number':\n output = Number(trimmedValue)\n break\n\n default:\n output = value\n }\n\n return output\n }\n\n /**\n * Parse dataset\n *\n * Loop over an object and normalise each value using {@link normaliseString},\n * optionally expanding nested `i18n.field`\n *\n * @param {Schema} schema - component schema\n * @param {DOMStringMap} dataset - HTML element dataset\n * @returns {object} Normalised dataset\n */\n parseDataset(schema, dataset) {\n const parsed = {}\n\n for (const [field, property] of Object.entries(schema.properties)) {\n if (field in dataset) {\n if (dataset[field]) {\n parsed[field] = this.normaliseString(dataset[field], property)\n }\n }\n }\n\n return parsed\n }\n\n /**\n * Config merging function\n *\n * Takes any number of objects and combines them together, with\n * greatest priority on the LAST item passed in.\n *\n * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge\n * @returns {{ [key: string]: unknown }} A merged config object\n */\n mergeConfigs(...configObjects) {\n const formattedConfigObject = {}\n\n // Loop through each of the passed objects\n for (const configObject of configObjects) {\n for (const key of Object.keys(configObject)) {\n const option = formattedConfigObject[key]\n const override = configObject[key]\n\n // Push their keys one-by-one into formattedConfigObject. Any duplicate\n // keys with object values will be merged, otherwise the new value will\n // override the existing value.\n if (typeof option === 'object' && typeof override === 'object') {\n // @ts-expect-error Index signature for type 'string' is missing\n formattedConfigObject[key] = this.mergeConfigs(option, override)\n } else {\n formattedConfigObject[key] = override\n }\n }\n }\n\n return formattedConfigObject\n }\n}\n\n/**\n * @typedef {object} AlertConfig\n * @property {boolean} [dismissible=false] - Can the alert be dismissed by the user\n * @property {string} [dismissText=Dismiss] - the label text for the dismiss button\n * @property {boolean} [disableAutoFocus=false] - whether the alert will be autofocused\n * @property {string} [focusOnDismissSelector] - CSS Selector for element to be focused on dismiss\n */\n"],"names":["Alert","constructor","$module","config","HTMLElement","schema","Object","freeze","properties","dismissible","type","dismissText","disableAutoFocus","focusOnDismissSelector","defaults","mergeConfigs","parseDataset","dataset","getAttribute","setFocus","$dismissButton","querySelector","innerHTML","removeAttribute","addEventListener","event","target","Node","contains","dimiss","$elementToRecieveFocus","document","$nextSibling","nextElementSibling","matches","getPreviousSibling","findNearestMatchingElement","remove","normaliseString","value","property","trimmedValue","trim","output","outputType","includes","length","Number","isFinite","parsed","field","entries","configObjects","formattedConfigObject","configObject","key","keys","option","override"],"mappings":"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"}
1
+ {"version":3,"file":"alert.mjs","sources":["../../../../src/moj/components/alert/alert.mjs"],"sourcesContent":["import { ConfigurableComponent } from 'govuk-frontend'\n\nimport { setFocus } from '../../common/index.mjs'\nimport {\n findNearestMatchingElement,\n getPreviousSibling\n} from '../../helpers.mjs'\n\n/**\n * @augments {ConfigurableComponent<AlertConfig>}\n */\nexport class Alert extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for alert\n * @param {AlertConfig} [config] - Alert config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n /**\n * Focus the alert\n *\n * If `role=\"alert\"` is set, focus the element to help some assistive\n * technologies prioritise announcing it.\n *\n * You can turn off the auto-focus functionality by setting\n * `data-disable-auto-focus=\"true\"` in the component HTML. You might wish to\n * do this based on user research findings, or to avoid a clash with another\n * element which should be focused when the page loads.\n */\n if (\n this.$root.getAttribute('role') === 'alert' &&\n !this.config.disableAutoFocus\n ) {\n setFocus(this.$root)\n }\n\n this.$dismissButton = this.$root.querySelector('.moj-alert__dismiss')\n\n if (this.config.dismissible && this.$dismissButton) {\n this.$dismissButton.innerHTML = this.config.dismissText\n this.$dismissButton.removeAttribute('hidden')\n\n this.$root.addEventListener('click', (event) => {\n if (\n event.target instanceof Node &&\n this.$dismissButton.contains(event.target)\n ) {\n this.dimiss()\n }\n })\n }\n }\n\n /**\n * Handle dismissing the alert\n */\n dimiss() {\n let $elementToRecieveFocus\n\n // If a selector has been provided, attempt to find that element\n if (this.config.focusOnDismissSelector) {\n $elementToRecieveFocus = document.querySelector(\n this.config.focusOnDismissSelector\n )\n }\n\n // Is the next sibling another alert\n if (!$elementToRecieveFocus) {\n const $nextSibling = this.$root.nextElementSibling\n if ($nextSibling && $nextSibling.matches('.moj-alert')) {\n $elementToRecieveFocus = $nextSibling\n }\n }\n\n // Else try to find any preceding sibling alert or heading\n if (!$elementToRecieveFocus) {\n $elementToRecieveFocus = getPreviousSibling(\n this.$root,\n '.moj-alert, h1, h2, h3, h4, h5, h6'\n )\n }\n\n // Else find the closest ancestor heading, or fallback to main, or last resort\n // use the body element\n if (!$elementToRecieveFocus) {\n $elementToRecieveFocus = findNearestMatchingElement(\n this.$root,\n 'h1, h2, h3, h4, h5, h6, main, body'\n )\n }\n\n // If we have an element, place focus on it\n if ($elementToRecieveFocus instanceof HTMLElement) {\n setFocus($elementToRecieveFocus)\n }\n\n // Remove the alert\n this.$root.remove()\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-alert'\n\n /**\n * Alert default config\n *\n * @type {AlertConfig}\n */\n static defaults = Object.freeze({\n dismissible: false,\n dismissText: 'Dismiss',\n disableAutoFocus: false\n })\n\n /**\n * Alert config schema\n *\n * @satisfies {Schema<AlertConfig>}\n */\n static schema = Object.freeze(\n /** @type {const} */ ({\n properties: {\n dismissible: { type: 'boolean' },\n dismissText: { type: 'string' },\n disableAutoFocus: { type: 'boolean' },\n focusOnDismissSelector: { type: 'string' }\n }\n })\n )\n}\n\n/**\n * @typedef {object} AlertConfig\n * @property {boolean} [dismissible=false] - Can the alert be dismissed by the user\n * @property {string} [dismissText=Dismiss] - the label text for the dismiss button\n * @property {boolean} [disableAutoFocus=false] - whether the alert will be autofocused\n * @property {string} [focusOnDismissSelector] - CSS Selector for element to be focused on dismiss\n */\n\n/**\n * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'\n */\n"],"names":["Alert","ConfigurableComponent","constructor","$root","config","getAttribute","disableAutoFocus","setFocus","$dismissButton","querySelector","dismissible","innerHTML","dismissText","removeAttribute","addEventListener","event","target","Node","contains","dimiss","$elementToRecieveFocus","focusOnDismissSelector","document","$nextSibling","nextElementSibling","matches","getPreviousSibling","findNearestMatchingElement","HTMLElement","remove","moduleName","defaults","Object","freeze","schema","properties","type"],"mappings":"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"}
@@ -31,7 +31,9 @@ The JavaScript
31
31
  ```mjs
32
32
  import { ButtonMenu } from '@ministryofjustice/frontend'
33
33
 
34
- const $buttonMenu = document.querySelector('.app-button-menu')
34
+ const $buttonMenu = document.querySelector(
35
+ '[data-module="moj-button-menu"]'
36
+ )
35
37
 
36
38
  new ButtonMenu($buttonMenu, {
37
39
  alignMenu: 'right',