defra_ruby_template 6.4.0 → 6.6.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.
- checksums.yaml +4 -4
- data/README.md +73 -19
- data/Rakefile +10 -33
- data/lib/defra_ruby_template/version.rb +1 -1
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +202 -137
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +202 -137
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/common/closest-attribute-value.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +5 -1
- data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/common/create-element.mjs +13 -0
- data/node_modules/govuk-frontend/dist/govuk/common/create-element.mjs.map +1 -0
- data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/common/index.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/component.mjs +2 -1
- data/node_modules/govuk-frontend/dist/govuk/component.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/_index.import.scss +2 -0
- data/node_modules/govuk-frontend/dist/govuk/components/_index.scss +2 -0
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +87 -62
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +87 -62
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +60 -56
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +90 -32
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +90 -32
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +64 -27
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/fixtures.json +173 -6
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/macro-options.json +13 -6
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-characters-and-error-message.html +12 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-characters-and-threshold.html +9 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-characters-and-value.html +9 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-characters.html +9 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-length.html +9 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-words-and-error-message.html +12 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-words-and-threshold.html +9 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-words-and-value.html +9 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-count-type-words.html +9 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-maxwords.html +9 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template.njk +10 -3
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/cookie-banner/_mixin.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +43 -18
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +43 -18
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs +16 -12
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/README.md +15 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/_feedback.import.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/_index.import.scss +8 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/_index.scss +5 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/_mixin.scss +48 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/fixtures.json +95 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/macro-options.json +50 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/macro.njk +3 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/template-default.html +12 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/template-silly-example.html +19 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/template.njk +24 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js +54 -30
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs +54 -30
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs +27 -24
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/footer/_mixin.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/README.md +15 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_index.import.scss +8 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_index.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_language-navigation.import.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_mixin.scss +68 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/fixtures.json +482 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/macro-options.json +88 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/macro.njk +3 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-default.html +12 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-inverse.html +12 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-with-language-description.html +12 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-with-large-amount-of-multiple-languages.html +99 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-with-mixed-text-directions.html +12 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-with-multiple-languages.html +24 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template-with-translated-navigation-label.html +12 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/template.njk +33 -0
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/panel/fixtures.json +13 -11
- data/node_modules/govuk-frontend/dist/govuk/components/panel/template-interruption-with-headings-content-and-lists.html +6 -1
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +32 -9
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +32 -9
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs +5 -3
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/_mixin.scss +48 -3
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/fixtures.json +121 -0
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/macro-options.json +20 -0
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-inverse-with-language-navigation.html +72 -0
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-inline-end-slot.html +33 -0
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-language-navigation.html +62 -0
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template-with-right-aligned-language-navigation.html +62 -0
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/template.njk +8 -3
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +14 -6
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +14 -6
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs +2 -1
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/custom-properties/_frontend-version.mixin.scss +1 -1
- data/node_modules/govuk-frontend/dist/govuk/custom-properties/_functional-colours.mixin.scss +1 -0
- data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs +8 -5
- data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css +2 -2
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss +1 -1
- data/node_modules/govuk-frontend/dist/govuk/i18n.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/init.mjs +8 -8
- data/node_modules/govuk-frontend/dist/govuk/init.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss +16 -2
- data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +9 -1
- data/node_modules/govuk-frontend/package.json +9 -7
- data/vendor/assets/javascripts/defra_ruby_template.js +202 -137
- data/vendor/assets/stylesheets/components/_index.import.scss +2 -0
- data/vendor/assets/stylesheets/components/_index.scss +2 -0
- data/vendor/assets/stylesheets/components/cookie-banner/_mixin.scss +6 -0
- data/vendor/assets/stylesheets/components/feedback/_feedback.import.scss +6 -0
- data/vendor/assets/stylesheets/components/feedback/_index.import.scss +8 -0
- data/vendor/assets/stylesheets/components/feedback/_index.scss +5 -0
- data/vendor/assets/stylesheets/components/feedback/_mixin.scss +48 -0
- data/vendor/assets/stylesheets/components/footer/_mixin.scss +6 -0
- data/vendor/assets/stylesheets/components/language-navigation/_index.import.scss +8 -0
- data/vendor/assets/stylesheets/components/language-navigation/_index.scss +6 -0
- data/vendor/assets/stylesheets/components/language-navigation/_language-navigation.import.scss +6 -0
- data/vendor/assets/stylesheets/components/language-navigation/_mixin.scss +68 -0
- data/vendor/assets/stylesheets/components/service-navigation/_mixin.scss +48 -3
- data/vendor/assets/stylesheets/custom-properties/_frontend-version.mixin.scss +1 -1
- data/vendor/assets/stylesheets/custom-properties/_functional-colours.mixin.scss +1 -0
- data/vendor/assets/stylesheets/defra_ruby_template.scss +8 -30
- data/vendor/assets/stylesheets/govuk-frontend.min.css +2 -2
- data/vendor/assets/stylesheets/helpers/_colour.scss +1 -1
- data/vendor/assets/stylesheets/settings/_colours-organisations.scss +16 -2
- metadata +53 -3
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template-with-word-count.html +0 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"closest-attribute-value.mjs","sources":["../../../src/govuk/common/closest-attribute-value.mjs"],"sourcesContent":["/**\n * Returns the value of the given attribute closest to the given element (including itself)\n *\n * @internal\n * @param {Element} $element - The element to start walking the DOM tree up\n * @param {string} attributeName - The name of the attribute\n * @returns {string | null} Attribute value\n */\nexport function closestAttributeValue($element, attributeName) {\n const $closestElementWithAttribute = $element.closest(`[${attributeName}]`)\n return $closestElementWithAttribute\n ? $closestElementWithAttribute.getAttribute(attributeName)\n : null\n}\n"],"names":["closestAttributeValue","$element","attributeName","$closestElementWithAttribute","closest","getAttribute"],"mappings":"AAQO,SAASA,qBAAqBA,CAACC,QAAQ,EAAEC,aAAa,EAAE;EAC7D,MAAMC,4BAA4B,GAAGF,QAAQ,CAACG,OAAO,CAAC,CAAA,CAAA,EAAIF,aAAa,CAAA,CAAA,CAAG,CAAC;EAC3E,OAAOC,4BAA4B,GAC/BA,4BAA4B,CAACE,YAAY,CAACH,aAAa,CAAC,GACxD,IAAI;AACV
|
|
1
|
+
{"version":3,"file":"closest-attribute-value.mjs","sources":["../../../src/govuk/common/closest-attribute-value.mjs"],"sourcesContent":["/**\n * Returns the value of the given attribute closest to the given element (including itself)\n *\n * @internal\n * @param {Element} $element - The element to start walking the DOM tree up\n * @param {string} attributeName - The name of the attribute\n * @returns {string | null} Attribute value\n */\nexport function closestAttributeValue($element, attributeName) {\n const $closestElementWithAttribute = $element.closest(`[${attributeName}]`)\n return $closestElementWithAttribute\n ? $closestElementWithAttribute.getAttribute(attributeName)\n : null\n}\n"],"names":["closestAttributeValue","$element","attributeName","$closestElementWithAttribute","closest","getAttribute"],"mappings":"AAQO,SAASA,qBAAqBA,CAACC,QAAQ,EAAEC,aAAa,EAAE;EAC7D,MAAMC,4BAA4B,GAAGF,QAAQ,CAACG,OAAO,CAAC,CAAA,CAAA,EAAIF,aAAa,CAAA,CAAA,CAAG,CAAC;EAC3E,OAAOC,4BAA4B,GAC/BA,4BAA4B,CAACE,YAAY,CAACH,aAAa,CAAC,GACxD,IAAI;AACV;;"}
|
|
@@ -25,10 +25,14 @@ class ConfigurableComponent extends Component {
|
|
|
25
25
|
throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
|
|
26
26
|
}
|
|
27
27
|
const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
|
|
28
|
-
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}
|
|
28
|
+
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
|
|
29
|
+
this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
function normaliseString(value, property) {
|
|
33
|
+
if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
32
36
|
const trimmedValue = value ? value.trim() : '';
|
|
33
37
|
let output;
|
|
34
38
|
let outputType = property == null ? void 0 : property.type;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configuration.mjs","sources":["../../../src/govuk/common/configuration.mjs"],"sourcesContent":["import { Component } from '../component.mjs'\nimport { ConfigError } from '../errors/index.mjs'\n\nimport { isObject, isScope, formatErrorMessage } from './index.mjs'\n\nexport const configOverride = Symbol.for('configOverride')\n\n/**\n * Base Component class\n *\n * Centralises the behaviours shared by our components\n *\n * @virtual\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]\n * @template {Element & { dataset: DOMStringMap }} [RootElementType=HTMLElement]\n * @augments Component<RootElementType>\n */\nexport class ConfigurableComponent extends Component {\n /**\n * configOverride\n *\n * Function which defines configuration overrides to prioritize\n * properties from the root element's dataset.\n *\n * It should take a subset of configuration as input and return\n * a new configuration object with properties that should be\n * overridden based on the root element's dataset. A Symbol\n * is used for indexing to prevent conflicts.\n *\n * @internal\n * @virtual\n * @param {Partial<ConfigurationType>} [param] - Configuration object\n * @returns {Partial<ConfigurationType>} return - Configuration object\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\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\n /**\n *\n * @type {ConfigurationType}\n */\n _config\n\n /**\n * Constructs a new component, validating that GOV.UK Frontend is supported\n *\n * @internal\n * @param {Element | null} [$root] - HTML element to use for component\n * @param {ConfigurationType} [config] - HTML element to use for component\n */\n constructor($root, config) {\n super($root)\n\n const childConstructor =\n /** @type {ChildClassConstructor<ConfigurationType>} */ (this.constructor)\n\n if (!isObject(childConstructor.defaults)) {\n throw new ConfigError(\n formatErrorMessage(\n childConstructor,\n 'Config passed as parameter into constructor but no defaults defined'\n )\n )\n }\n\n const datasetConfig = /** @type {ConfigurationType} */ (\n normaliseDataset(childConstructor, this._$root.dataset)\n )\n\n this._config = /** @type {ConfigurationType} */ (\n mergeConfigs(\n childConstructor.defaults,\n config ?? {},\n this[configOverride](datasetConfig),\n datasetConfig\n )\n )\n }\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 */\nexport function normaliseString(value, property) {\n const trimmedValue = value ? value.trim() : ''\n\n let output\n let outputType = property?.type\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 && 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 * Normalise dataset\n *\n * Loop over an object and normalise each value using {@link normaliseString},\n * optionally expanding nested `i18n.field`\n *\n * @internal\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @template {[keyof ConfigurationType, SchemaProperty | undefined][]} SchemaEntryType\n * @param {{ schema?: Schema<ConfigurationType>, moduleName: string }} Component - Component class\n * @param {DOMStringMap} dataset - HTML element dataset\n * @returns {ObjectNested} Normalised dataset\n */\nexport function normaliseDataset(Component, dataset) {\n if (!isObject(Component.schema)) {\n throw new ConfigError(\n formatErrorMessage(\n Component,\n 'Config passed as parameter into constructor but no schema defined'\n )\n )\n }\n\n const out = /** @type {ObjectNested} */ ({})\n const entries = /** @type {SchemaEntryType} */ (\n Object.entries(Component.schema.properties)\n )\n\n // Normalise top-level dataset ('data-*') values using schema types\n for (const entry of entries) {\n const [namespace, property] = entry\n\n // Cast the `namespace` to string so it can be used to access the dataset\n const field = namespace.toString()\n\n if (field in dataset) {\n out[field] = normaliseString(dataset[field], property)\n }\n\n /**\n * Extract and normalise nested object values automatically using\n * {@link normaliseString} but only schema object types are allowed\n */\n if (property?.type === 'object') {\n out[field] = extractConfigByNamespace(\n Component.schema,\n dataset,\n namespace\n )\n }\n }\n\n return out\n}\n\n/**\n * Normalise options passed to `initAll` or `createAll`\n *\n * @internal\n * @template {CompatibleClass} ComponentClass\n * @param {Config | CreateAllOptions<ComponentClass> | OnErrorCallback<ComponentClass> | Element | Document | null} [scopeOrOptions] - Scope of the document to search within, initialisation options or error callback function\n * @returns {CreateAllOptions<ComponentClass>} Normalised options\n */\nexport function normaliseOptions(scopeOrOptions) {\n let /** @type {Element | Document | null} */ $scope = document\n let /** @type {OnErrorCallback<ComponentClass> | undefined} */ onError\n\n // Handle options object\n if (isObject(scopeOrOptions)) {\n const options = scopeOrOptions\n\n // Scope must be valid or null\n if (isScope(options.scope) || options.scope === null) {\n $scope = options.scope\n }\n\n // Error handler must be a function\n if (typeof options.onError === 'function') {\n onError = options.onError\n }\n }\n\n if (isScope(scopeOrOptions)) {\n $scope = scopeOrOptions\n } else if (scopeOrOptions === null) {\n $scope = null\n } else if (typeof scopeOrOptions === 'function') {\n onError = scopeOrOptions\n }\n\n return {\n scope: $scope,\n onError\n }\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 * @internal\n * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge\n * @returns {{ [key: string]: unknown }} A merged config object\n */\nexport function mergeConfigs(...configObjects) {\n // Start with an empty object as our base\n /** @type {{ [key: string]: unknown }} */\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 (isObject(option) && isObject(override)) {\n formattedConfigObject[key] = mergeConfigs(option, override)\n } else {\n // Apply override\n formattedConfigObject[key] = override\n }\n }\n }\n\n return formattedConfigObject\n}\n\n/**\n * Validate component config by schema\n *\n * Follows limited examples in JSON schema for wider support in future\n *\n * {@link https://ajv.js.org/json-schema.html#compound-keywords}\n * {@link https://ajv.js.org/packages/ajv-errors.html#single-message}\n *\n * @internal\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @param {Schema<ConfigurationType>} schema - The schema of a component\n * @param {ConfigurationType} config - Component config\n * @returns {string[]} List of validation errors\n */\nexport function validateConfig(schema, config) {\n const validationErrors = []\n\n // Check errors for each schema\n for (const [name, conditions] of Object.entries(schema)) {\n const errors = []\n\n // Check errors for each schema condition\n if (Array.isArray(conditions)) {\n for (const { required, errorMessage } of conditions) {\n if (!required.every((key) => !!config[key])) {\n errors.push(errorMessage) // Missing config key value\n }\n }\n\n // Check one condition passes or add errors\n if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {\n validationErrors.push(...errors)\n }\n }\n }\n\n return validationErrors\n}\n\n/**\n * Extracts keys starting with a particular namespace from dataset ('data-*')\n * object, removing the namespace in the process, normalising all values\n *\n * @internal\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @param {Schema<ConfigurationType>} schema - The schema of a component\n * @param {DOMStringMap} dataset - The object to extract key-value pairs from\n * @param {keyof ConfigurationType} namespace - The namespace to filter keys with\n * @returns {ObjectNested | undefined} Nested object with dot-separated key namespace removed\n */\nexport function extractConfigByNamespace(schema, dataset, namespace) {\n const property = schema.properties[namespace]\n\n // Only extract configs for object schema properties\n if (property?.type !== 'object') {\n return\n }\n\n // Add default empty config\n const newObject = /** @type {Record<typeof namespace, ObjectNested>} */ ({\n [namespace]: {}\n })\n\n for (const [key, value] of Object.entries(dataset)) {\n /** @type {ObjectNested | ObjectNested[NestedKey]} */\n let current = newObject\n\n // Split the key into parts, using . as our namespace separator\n const keyParts = key.split('.')\n\n /**\n * Create new level per part\n *\n * e.g. 'i18n.textareaDescription.other' becomes\n * `{ i18n: { textareaDescription: { other } } }`\n */\n for (const [index, name] of keyParts.entries()) {\n if (isObject(current)) {\n // Drop down to nested object until the last part\n if (index < keyParts.length - 1) {\n // New nested object (optionally) replaces existing value\n if (!isObject(current[name])) {\n current[name] = {}\n }\n\n // Drop down into new or existing nested object\n current = current[name]\n } else if (key !== namespace) {\n // Normalised value (optionally) replaces existing value\n current[name] = normaliseString(value)\n }\n }\n }\n }\n\n return newObject[namespace]\n}\n\n/**\n * @internal\n * @typedef {keyof ObjectNested} NestedKey\n * @typedef {{ [key: string]: string | boolean | number | ObjectNested | undefined }} ObjectNested\n */\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/**\n * Schema property for component config\n *\n * @typedef {object} SchemaProperty\n * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type\n */\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/**\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/**\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]\n * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>\n */\n\n/**\n * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'\n */\n"],"names":["configOverride","Symbol","for","ConfigurableComponent","Component","param","config","_config","constructor","$root","childConstructor","isObject","defaults","ConfigError","formatErrorMessage","datasetConfig","normaliseDataset","_$root","dataset","mergeConfigs","normaliseString","value","property","trimmedValue","trim","output","outputType","type","includes","length","isFinite","Number","schema","out","entries","Object","properties","entry","namespace","field","toString","extractConfigByNamespace","normaliseOptions","scopeOrOptions","$scope","document","onError","options","isScope","scope","configObjects","formattedConfigObject","configObject","key","keys","option","override","validateConfig","validationErrors","name","conditions","errors","Array","isArray","required","errorMessage","every","push","newObject","current","keyParts","split","index"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"configuration.mjs","sources":["../../../src/govuk/common/configuration.mjs"],"sourcesContent":["import { Component } from '../component.mjs'\nimport { ConfigError } from '../errors/index.mjs'\n\nimport { isObject, isScope, formatErrorMessage } from './index.mjs'\n\nexport const configOverride = Symbol.for('configOverride')\n\n/**\n * Base Component class\n *\n * Centralises the behaviours shared by our components\n *\n * @virtual\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]\n * @template {Element & { dataset: DOMStringMap }} [RootElementType=HTMLElement]\n * @augments Component<RootElementType>\n */\nexport class ConfigurableComponent extends Component {\n /**\n * configOverride\n *\n * Function which defines configuration overrides to prioritize\n * properties from the root element's dataset.\n *\n * It should take a subset of configuration as input and return\n * a new configuration object with properties that should be\n * overridden based on the root element's dataset. A Symbol\n * is used for indexing to prevent conflicts.\n *\n * @internal\n * @virtual\n * @param {Partial<ConfigurationType>} [param] - Configuration object\n * @returns {Partial<ConfigurationType>} return - Configuration object\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\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\n /**\n *\n * @type {ConfigurationType}\n */\n _config\n\n /**\n * Constructs a new component, validating that GOV.UK Frontend is supported\n *\n * @internal\n * @param {Element | null} [$root] - HTML element to use for component\n * @param {ConfigurationType} [config] - HTML element to use for component\n */\n constructor($root, config) {\n super($root)\n\n const childConstructor =\n /** @type {ChildClassConstructor<ConfigurationType>} */ (this.constructor)\n\n if (!isObject(childConstructor.defaults)) {\n throw new ConfigError(\n formatErrorMessage(\n childConstructor,\n 'Config passed as parameter into constructor but no defaults defined'\n )\n )\n }\n\n const datasetConfig = /** @type {ConfigurationType} */ (\n normaliseDataset(childConstructor, this._$root.dataset)\n )\n\n // Override defaults with JavaScript config\n this._config = /** @type {ConfigurationType} */ (\n mergeConfigs(childConstructor.defaults, config ?? {})\n )\n\n // Override merged config with dataset config\n this._config = /** @type {ConfigurationType} */ (\n mergeConfigs(\n this._config,\n this[configOverride](datasetConfig),\n datasetConfig\n )\n )\n }\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 */\nexport function normaliseString(value, property) {\n if (\n property?.type &&\n !['string', 'number', 'boolean'].includes(property.type)\n ) {\n return\n }\n\n const trimmedValue = value ? value.trim() : ''\n\n let output\n let outputType = property?.type\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 && 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 * Normalise dataset\n *\n * Loop over an object and normalise each value using {@link normaliseString},\n * optionally expanding nested `i18n.field`\n *\n * @internal\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @template {[keyof ConfigurationType, SchemaProperty | undefined][]} SchemaEntryType\n * @param {{ schema?: Schema<ConfigurationType>, moduleName: string }} Component - Component class\n * @param {DOMStringMap} dataset - HTML element dataset\n * @returns {ObjectNested} Normalised dataset\n */\nexport function normaliseDataset(Component, dataset) {\n if (!isObject(Component.schema)) {\n throw new ConfigError(\n formatErrorMessage(\n Component,\n 'Config passed as parameter into constructor but no schema defined'\n )\n )\n }\n\n const out = /** @type {ObjectNested} */ ({})\n const entries = /** @type {SchemaEntryType} */ (\n Object.entries(Component.schema.properties)\n )\n\n // Normalise top-level dataset ('data-*') values using schema types\n for (const entry of entries) {\n const [namespace, property] = entry\n\n // Cast the `namespace` to string so it can be used to access the dataset\n const field = namespace.toString()\n\n if (field in dataset) {\n out[field] = normaliseString(dataset[field], property)\n }\n\n /**\n * Extract and normalise nested object values automatically using\n * {@link normaliseString} but only schema object types are allowed\n */\n if (property?.type === 'object') {\n out[field] = extractConfigByNamespace(\n Component.schema,\n dataset,\n namespace\n )\n }\n }\n\n return out\n}\n\n/**\n * Normalise options passed to `initAll` or `createAll`\n *\n * @internal\n * @template {CompatibleClass} ComponentClass\n * @param {Config | CreateAllOptions<ComponentClass> | OnErrorCallback<ComponentClass> | Element | Document | null} [scopeOrOptions] - Scope of the document to search within, initialisation options or error callback function\n * @returns {CreateAllOptions<ComponentClass>} Normalised options\n */\nexport function normaliseOptions(scopeOrOptions) {\n let /** @type {Element | Document | null} */ $scope = document\n let /** @type {OnErrorCallback<ComponentClass> | undefined} */ onError\n\n // Handle options object\n if (isObject(scopeOrOptions)) {\n const options = scopeOrOptions\n\n // Scope must be valid or null\n if (isScope(options.scope) || options.scope === null) {\n $scope = options.scope\n }\n\n // Error handler must be a function\n if (typeof options.onError === 'function') {\n onError = options.onError\n }\n }\n\n if (isScope(scopeOrOptions)) {\n $scope = scopeOrOptions\n } else if (scopeOrOptions === null) {\n $scope = null\n } else if (typeof scopeOrOptions === 'function') {\n onError = scopeOrOptions\n }\n\n return {\n scope: $scope,\n onError\n }\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 * @internal\n * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge\n * @returns {{ [key: string]: unknown }} A merged config object\n */\nexport function mergeConfigs(...configObjects) {\n // Start with an empty object as our base\n /** @type {{ [key: string]: unknown }} */\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 (isObject(option) && isObject(override)) {\n formattedConfigObject[key] = mergeConfigs(option, override)\n } else {\n // Apply override\n formattedConfigObject[key] = override\n }\n }\n }\n\n return formattedConfigObject\n}\n\n/**\n * Validate component config by schema\n *\n * Follows limited examples in JSON schema for wider support in future\n *\n * {@link https://ajv.js.org/json-schema.html#compound-keywords}\n * {@link https://ajv.js.org/packages/ajv-errors.html#single-message}\n *\n * @internal\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @param {Schema<ConfigurationType>} schema - The schema of a component\n * @param {ConfigurationType} config - Component config\n * @returns {string[]} List of validation errors\n */\nexport function validateConfig(schema, config) {\n const validationErrors = []\n\n // Check errors for each schema\n for (const [name, conditions] of Object.entries(schema)) {\n const errors = []\n\n // Check errors for each schema condition\n if (Array.isArray(conditions)) {\n for (const { required, errorMessage } of conditions) {\n if (!required.every((key) => !!config[key])) {\n errors.push(errorMessage) // Missing config key value\n }\n }\n\n // Check one condition passes or add errors\n if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {\n validationErrors.push(...errors)\n }\n }\n }\n\n return validationErrors\n}\n\n/**\n * Extracts keys starting with a particular namespace from dataset ('data-*')\n * object, removing the namespace in the process, normalising all values\n *\n * @internal\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType\n * @param {Schema<ConfigurationType>} schema - The schema of a component\n * @param {DOMStringMap} dataset - The object to extract key-value pairs from\n * @param {keyof ConfigurationType} namespace - The namespace to filter keys with\n * @returns {ObjectNested | undefined} Nested object with dot-separated key namespace removed\n */\nexport function extractConfigByNamespace(schema, dataset, namespace) {\n const property = schema.properties[namespace]\n\n // Only extract configs for object schema properties\n if (property?.type !== 'object') {\n return\n }\n\n // Add default empty config\n const newObject = /** @type {Record<typeof namespace, ObjectNested>} */ ({\n [namespace]: {}\n })\n\n for (const [key, value] of Object.entries(dataset)) {\n /** @type {ObjectNested | ObjectNested[NestedKey]} */\n let current = newObject\n\n // Split the key into parts, using . as our namespace separator\n const keyParts = key.split('.')\n\n /**\n * Create new level per part\n *\n * e.g. 'i18n.textareaDescription.other' becomes\n * `{ i18n: { textareaDescription: { other } } }`\n */\n for (const [index, name] of keyParts.entries()) {\n if (isObject(current)) {\n // Drop down to nested object until the last part\n if (index < keyParts.length - 1) {\n // New nested object (optionally) replaces existing value\n if (!isObject(current[name])) {\n current[name] = {}\n }\n\n // Drop down into new or existing nested object\n current = current[name]\n } else if (key !== namespace) {\n // Normalised value (optionally) replaces existing value\n current[name] = normaliseString(value)\n }\n }\n }\n }\n\n return newObject[namespace]\n}\n\n/**\n * @internal\n * @typedef {keyof ObjectNested} NestedKey\n * @typedef {{ [key: string]: string | boolean | number | ObjectNested | undefined }} ObjectNested\n */\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/**\n * Schema property for component config\n *\n * @typedef {object} SchemaProperty\n * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type\n */\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/**\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/**\n * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]\n * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>\n */\n\n/**\n * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'\n */\n"],"names":["configOverride","Symbol","for","ConfigurableComponent","Component","param","config","_config","constructor","$root","childConstructor","isObject","defaults","ConfigError","formatErrorMessage","datasetConfig","normaliseDataset","_$root","dataset","mergeConfigs","normaliseString","value","property","type","includes","trimmedValue","trim","output","outputType","length","isFinite","Number","schema","out","entries","Object","properties","entry","namespace","field","toString","extractConfigByNamespace","normaliseOptions","scopeOrOptions","$scope","document","onError","options","isScope","scope","configObjects","formattedConfigObject","configObject","key","keys","option","override","validateConfig","validationErrors","name","conditions","errors","Array","isArray","required","errorMessage","every","push","newObject","current","keyParts","split","index"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function createElement(tagName, attributes = {}, children = []) {
|
|
2
|
+
const $element = document.createElement(tagName);
|
|
3
|
+
Object.entries(attributes).forEach(([name, value]) => {
|
|
4
|
+
$element.setAttribute(name, value);
|
|
5
|
+
});
|
|
6
|
+
for (const child of children) {
|
|
7
|
+
$element.append(child);
|
|
8
|
+
}
|
|
9
|
+
return $element;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { createElement };
|
|
13
|
+
//# sourceMappingURL=create-element.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-element.mjs","sources":["../../../src/govuk/common/create-element.mjs"],"sourcesContent":["/**\n * Creates an element with the given attributes and child elements\n *\n * @internal\n * @template {keyof HTMLElementTagNameMap} TagName\n * @param {TagName} tagName - Type of element to create\n * @param {{[key: string]: string}} [attributes] - Attributes to set on the element\n * @param {Array<HTMLElement | string>} [children] - An optional list of children or text to append to the element\n * @returns {HTMLElementTagNameMap[TagName]} Created element\n */\nexport function createElement(tagName, attributes = {}, children = []) {\n const $element = document.createElement(tagName)\n\n Object.entries(attributes).forEach(([name, value]) => {\n $element.setAttribute(name, value)\n })\n\n for (const child of children) {\n $element.append(child)\n }\n\n return $element\n}\n"],"names":["createElement","tagName","attributes","children","$element","document","Object","entries","forEach","name","value","setAttribute","child","append"],"mappings":"AAUO,SAASA,aAAaA,CAACC,OAAO,EAAEC,UAAU,GAAG,EAAE,EAAEC,QAAQ,GAAG,EAAE,EAAE;AACrE,EAAA,MAAMC,QAAQ,GAAGC,QAAQ,CAACL,aAAa,CAACC,OAAO,CAAC;AAEhDK,EAAAA,MAAM,CAACC,OAAO,CAACL,UAAU,CAAC,CAACM,OAAO,CAAC,CAAC,CAACC,IAAI,EAAEC,KAAK,CAAC,KAAK;AACpDN,IAAAA,QAAQ,CAACO,YAAY,CAACF,IAAI,EAAEC,KAAK,CAAC;AACpC,EAAA,CAAC,CAAC;AAEF,EAAA,KAAK,MAAME,KAAK,IAAIT,QAAQ,EAAE;AAC5BC,IAAAA,QAAQ,CAACS,MAAM,CAACD,KAAK,CAAC;AACxB,EAAA;AAEA,EAAA,OAAOR,QAAQ;AACjB;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"govuk-frontend-version.mjs","sources":["../../../src/govuk/common/govuk-frontend-version.mjs"],"sourcesContent":["/*\n * This variable is automatically overwritten during builds and releases.\n * It doesn't need to be updated manually.\n */\n\n/**\n * GOV.UK Frontend release version\n *\n * {@link https://github.com/alphagov/govuk-frontend/releases}\n */\nexport const version = 'development'\n"],"names":["version"],"mappings":"AAUO,MAAMA,OAAO,GAAG
|
|
1
|
+
{"version":3,"file":"govuk-frontend-version.mjs","sources":["../../../src/govuk/common/govuk-frontend-version.mjs"],"sourcesContent":["/*\n * This variable is automatically overwritten during builds and releases.\n * It doesn't need to be updated manually.\n */\n\n/**\n * GOV.UK Frontend release version\n *\n * {@link https://github.com/alphagov/govuk-frontend/releases}\n */\nexport const version = 'development'\n"],"names":["version"],"mappings":"AAUO,MAAMA,OAAO,GAAG;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../../src/govuk/common/index.mjs"],"sourcesContent":["/**\n * Common helpers which do not require polyfill.\n *\n * IMPORTANT: If a helper require a polyfill, please isolate it in its own module\n * so that the polyfill can be properly tree-shaken and does not burden\n * the components that do not need that helper\n */\n\n/**\n * Get GOV.UK Frontend breakpoint value from CSS custom property\n *\n * @private\n * @param {string} name - Breakpoint name\n * @returns {{ property: string, value?: string }} Breakpoint object\n */\nexport function getBreakpoint(name) {\n const property = `--govuk-breakpoint-${name}`\n\n // Get value from `<html>` with breakpoints on CSS :root\n const value = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(property)\n\n return {\n property,\n value: value || undefined\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 * @private\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/**\n * Checks if component is already initialised\n *\n * @internal\n * @param {Element} $root - HTML element to be checked\n * @param {string} moduleName - name of component module\n * @returns {boolean} Whether component is already initialised\n */\nexport function isInitialised($root, moduleName) {\n return (\n $root instanceof HTMLElement &&\n $root.hasAttribute(`data-${moduleName}-init`)\n )\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 */\nexport function isSupported($scope = document.body) {\n if (!$scope) {\n return false\n }\n\n return $scope.classList.contains('govuk-frontend-supported')\n}\n\n/**\n * Check for an array\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an array\n */\nfunction isArray(option) {\n return Array.isArray(option)\n}\n\n/**\n * Check for an object\n *\n * @internal\n * @template {Partial<Record<keyof ObjectType, unknown>>} ObjectType\n * @param {unknown | ObjectType} option - Option to check\n * @returns {option is ObjectType} Whether the option is an object\n */\nexport function isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option)\n}\n\n/**\n * Check for valid scope\n *\n * @internal\n * @template {Element | Document} ScopeType\n * @param {unknown | ScopeType} $scope - Scope of the document to search within\n * @returns {$scope is ScopeType} Whether the scope can be queried\n */\nexport function isScope($scope) {\n return !!$scope && ($scope instanceof Element || $scope instanceof Document)\n}\n\n/**\n * Format error message\n *\n * @internal\n * @param {ComponentWithModuleName} Component - Component that threw the error\n * @param {string} message - Error message\n * @returns {string} - Formatted error message\n */\nexport function formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`\n}\n\n/* eslint-disable jsdoc/valid-types --\n * `{new(...args: any[] ): object}` is not recognised as valid\n * https://github.com/gajus/eslint-plugin-jsdoc/issues/145#issuecomment-1308722878\n * https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/131\n **/\n\n/**\n * @typedef ComponentWithModuleName\n * @property {string} moduleName - Name of the component\n */\n\n/* eslint-enable jsdoc/valid-types */\n"],"names":["getBreakpoint","name","property","value","window","getComputedStyle","document","documentElement","getPropertyValue","undefined","setFocus","$element","options","_options$onBeforeFocu","isFocusable","getAttribute","setAttribute","onFocus","addEventListener","onBlur","once","_options$onBlur","call","removeAttribute","onBeforeFocus","focus","isInitialised","$root","moduleName","HTMLElement","hasAttribute","isSupported","$scope","body","classList","contains","isArray","option","Array","isObject","isScope","Element","Document","formatErrorMessage","Component","message"],"mappings":"AAeO,SAASA,aAAaA,CAACC,IAAI,EAAE;AAClC,EAAA,MAAMC,QAAQ,GAAG,CAAA,mBAAA,EAAsBD,IAAI,CAAA,CAAE;AAG7C,EAAA,MAAME,KAAK,GAAGC,MAAM,CACjBC,gBAAgB,CAACC,QAAQ,CAACC,eAAe,CAAC,CAC1CC,gBAAgB,CAACN,QAAQ,CAAC;EAE7B,OAAO;IACLA,QAAQ;IACRC,KAAK,EAAEA,KAAK,IAAIM;GACjB;AACH;AAeO,SAASC,QAAQA,CAACC,QAAQ,EAAEC,OAAO,GAAG,EAAE,EAAE;AAAA,EAAA,IAAAC,qBAAA;AAC/C,EAAA,MAAMC,WAAW,GAAGH,QAAQ,CAACI,YAAY,CAAC,UAAU,CAAC;EAErD,IAAI,CAACD,WAAW,EAAE;AAChBH,IAAAA,QAAQ,CAACK,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC;AACzC,EAAA;EAKA,SAASC,OAAOA,GAAG;AACjBN,IAAAA,QAAQ,CAACO,gBAAgB,CAAC,MAAM,EAAEC,MAAM,EAAE;AAAEC,MAAAA,IAAI,EAAE;AAAK,KAAC,CAAC;AAC3D,EAAA;EAKA,SAASD,MAAMA,GAAG;AAAA,IAAA,IAAAE,eAAA;IAChB,CAAAA,eAAA,GAAAT,OAAO,CAACO,MAAM,KAAA,IAAA,IAAdE,eAAA,CAAgBC,IAAI,CAACX,QAAQ,CAAC;IAE9B,IAAI,CAACG,WAAW,EAAE;AAChBH,MAAAA,QAAQ,CAACY,eAAe,CAAC,UAAU,CAAC;AACtC,IAAA;AACF,EAAA;AAGAZ,EAAAA,QAAQ,CAACO,gBAAgB,CAAC,OAAO,EAAED,OAAO,EAAE;AAAEG,IAAAA,IAAI,EAAE;AAAK,GAAC,CAAC;EAG3D,CAAAP,qBAAA,GAAAD,OAAO,CAACY,aAAa,KAAA,IAAA,IAArBX,qBAAA,CAAuBS,IAAI,CAACX,QAAQ,CAAC;EACrCA,QAAQ,CAACc,KAAK,EAAE;AAClB;AAUO,SAASC,aAAaA,CAACC,KAAK,EAAEC,UAAU,EAAE;EAC/C,OACED,KAAK,YAAYE,WAAW,IAC5BF,KAAK,CAACG,YAAY,CAAC,CAAA,KAAA,EAAQF,UAAU,CAAA,KAAA,CAAO,CAAC;AAEjD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,WAAWA,CAACC,MAAM,GAAG1B,QAAQ,CAAC2B,IAAI,EAAE;EAClD,IAAI,CAACD,MAAM,EAAE;AACX,IAAA,OAAO,KAAK;AACd,EAAA;AAEA,EAAA,OAAOA,MAAM,CAACE,SAAS,CAACC,QAAQ,CAAC,0BAA0B,CAAC;AAC9D;AASA,SAASC,OAAOA,CAACC,MAAM,EAAE;AACvB,EAAA,OAAOC,KAAK,CAACF,OAAO,CAACC,MAAM,CAAC;AAC9B;AAUO,SAASE,QAAQA,CAACF,MAAM,EAAE;AAC/B,EAAA,OAAO,CAAC,CAACA,MAAM,IAAI,OAAOA,MAAM,KAAK,QAAQ,IAAI,CAACD,OAAO,CAACC,MAAM,CAAC;AACnE;AAUO,SAASG,OAAOA,CAACR,MAAM,EAAE;EAC9B,OAAO,CAAC,CAACA,MAAM,KAAKA,MAAM,YAAYS,OAAO,IAAIT,MAAM,YAAYU,QAAQ,CAAC;AAC9E;AAUO,SAASC,kBAAkBA,CAACC,SAAS,EAAEC,OAAO,EAAE;AACrD,EAAA,OAAO,GAAGD,SAAS,CAAChB,UAAU,CAAA,EAAA,EAAKiB,OAAO,CAAA,CAAE;AAC9C;AAQA;AACA;AACA;AACA
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../../src/govuk/common/index.mjs"],"sourcesContent":["/**\n * Common helpers which do not require polyfill.\n *\n * IMPORTANT: If a helper require a polyfill, please isolate it in its own module\n * so that the polyfill can be properly tree-shaken and does not burden\n * the components that do not need that helper\n */\n\n/**\n * Get GOV.UK Frontend breakpoint value from CSS custom property\n *\n * @private\n * @param {string} name - Breakpoint name\n * @returns {{ property: string, value?: string }} Breakpoint object\n */\nexport function getBreakpoint(name) {\n const property = `--govuk-breakpoint-${name}`\n\n // Get value from `<html>` with breakpoints on CSS :root\n const value = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(property)\n\n return {\n property,\n value: value || undefined\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 * @private\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/**\n * Checks if component is already initialised\n *\n * @internal\n * @param {Element} $root - HTML element to be checked\n * @param {string} moduleName - name of component module\n * @returns {boolean} Whether component is already initialised\n */\nexport function isInitialised($root, moduleName) {\n return (\n $root instanceof HTMLElement &&\n $root.hasAttribute(`data-${moduleName}-init`)\n )\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 */\nexport function isSupported($scope = document.body) {\n if (!$scope) {\n return false\n }\n\n return $scope.classList.contains('govuk-frontend-supported')\n}\n\n/**\n * Check for an array\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an array\n */\nfunction isArray(option) {\n return Array.isArray(option)\n}\n\n/**\n * Check for an object\n *\n * @internal\n * @template {Partial<Record<keyof ObjectType, unknown>>} ObjectType\n * @param {unknown | ObjectType} option - Option to check\n * @returns {option is ObjectType} Whether the option is an object\n */\nexport function isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option)\n}\n\n/**\n * Check for valid scope\n *\n * @internal\n * @template {Element | Document} ScopeType\n * @param {unknown | ScopeType} $scope - Scope of the document to search within\n * @returns {$scope is ScopeType} Whether the scope can be queried\n */\nexport function isScope($scope) {\n return !!$scope && ($scope instanceof Element || $scope instanceof Document)\n}\n\n/**\n * Format error message\n *\n * @internal\n * @param {ComponentWithModuleName} Component - Component that threw the error\n * @param {string} message - Error message\n * @returns {string} - Formatted error message\n */\nexport function formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`\n}\n\n/* eslint-disable jsdoc/valid-types --\n * `{new(...args: any[] ): object}` is not recognised as valid\n * https://github.com/gajus/eslint-plugin-jsdoc/issues/145#issuecomment-1308722878\n * https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/131\n **/\n\n/**\n * @typedef ComponentWithModuleName\n * @property {string} moduleName - Name of the component\n */\n\n/* eslint-enable jsdoc/valid-types */\n"],"names":["getBreakpoint","name","property","value","window","getComputedStyle","document","documentElement","getPropertyValue","undefined","setFocus","$element","options","_options$onBeforeFocu","isFocusable","getAttribute","setAttribute","onFocus","addEventListener","onBlur","once","_options$onBlur","call","removeAttribute","onBeforeFocus","focus","isInitialised","$root","moduleName","HTMLElement","hasAttribute","isSupported","$scope","body","classList","contains","isArray","option","Array","isObject","isScope","Element","Document","formatErrorMessage","Component","message"],"mappings":"AAeO,SAASA,aAAaA,CAACC,IAAI,EAAE;AAClC,EAAA,MAAMC,QAAQ,GAAG,CAAA,mBAAA,EAAsBD,IAAI,CAAA,CAAE;AAG7C,EAAA,MAAME,KAAK,GAAGC,MAAM,CACjBC,gBAAgB,CAACC,QAAQ,CAACC,eAAe,CAAC,CAC1CC,gBAAgB,CAACN,QAAQ,CAAC;EAE7B,OAAO;IACLA,QAAQ;IACRC,KAAK,EAAEA,KAAK,IAAIM;GACjB;AACH;AAeO,SAASC,QAAQA,CAACC,QAAQ,EAAEC,OAAO,GAAG,EAAE,EAAE;AAAA,EAAA,IAAAC,qBAAA;AAC/C,EAAA,MAAMC,WAAW,GAAGH,QAAQ,CAACI,YAAY,CAAC,UAAU,CAAC;EAErD,IAAI,CAACD,WAAW,EAAE;AAChBH,IAAAA,QAAQ,CAACK,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC;AACzC,EAAA;EAKA,SAASC,OAAOA,GAAG;AACjBN,IAAAA,QAAQ,CAACO,gBAAgB,CAAC,MAAM,EAAEC,MAAM,EAAE;AAAEC,MAAAA,IAAI,EAAE;AAAK,KAAC,CAAC;AAC3D,EAAA;EAKA,SAASD,MAAMA,GAAG;AAAA,IAAA,IAAAE,eAAA;IAChB,CAAAA,eAAA,GAAAT,OAAO,CAACO,MAAM,KAAA,IAAA,IAAdE,eAAA,CAAgBC,IAAI,CAACX,QAAQ,CAAC;IAE9B,IAAI,CAACG,WAAW,EAAE;AAChBH,MAAAA,QAAQ,CAACY,eAAe,CAAC,UAAU,CAAC;AACtC,IAAA;AACF,EAAA;AAGAZ,EAAAA,QAAQ,CAACO,gBAAgB,CAAC,OAAO,EAAED,OAAO,EAAE;AAAEG,IAAAA,IAAI,EAAE;AAAK,GAAC,CAAC;EAG3D,CAAAP,qBAAA,GAAAD,OAAO,CAACY,aAAa,KAAA,IAAA,IAArBX,qBAAA,CAAuBS,IAAI,CAACX,QAAQ,CAAC;EACrCA,QAAQ,CAACc,KAAK,EAAE;AAClB;AAUO,SAASC,aAAaA,CAACC,KAAK,EAAEC,UAAU,EAAE;EAC/C,OACED,KAAK,YAAYE,WAAW,IAC5BF,KAAK,CAACG,YAAY,CAAC,CAAA,KAAA,EAAQF,UAAU,CAAA,KAAA,CAAO,CAAC;AAEjD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,WAAWA,CAACC,MAAM,GAAG1B,QAAQ,CAAC2B,IAAI,EAAE;EAClD,IAAI,CAACD,MAAM,EAAE;AACX,IAAA,OAAO,KAAK;AACd,EAAA;AAEA,EAAA,OAAOA,MAAM,CAACE,SAAS,CAACC,QAAQ,CAAC,0BAA0B,CAAC;AAC9D;AASA,SAASC,OAAOA,CAACC,MAAM,EAAE;AACvB,EAAA,OAAOC,KAAK,CAACF,OAAO,CAACC,MAAM,CAAC;AAC9B;AAUO,SAASE,QAAQA,CAACF,MAAM,EAAE;AAC/B,EAAA,OAAO,CAAC,CAACA,MAAM,IAAI,OAAOA,MAAM,KAAK,QAAQ,IAAI,CAACD,OAAO,CAACC,MAAM,CAAC;AACnE;AAUO,SAASG,OAAOA,CAACR,MAAM,EAAE;EAC9B,OAAO,CAAC,CAACA,MAAM,KAAKA,MAAM,YAAYS,OAAO,IAAIT,MAAM,YAAYU,QAAQ,CAAC;AAC9E;AAUO,SAASC,kBAAkBA,CAACC,SAAS,EAAEC,OAAO,EAAE;AACrD,EAAA,OAAO,GAAGD,SAAS,CAAChB,UAAU,CAAA,EAAA,EAAKiB,OAAO,CAAA,CAAE;AAC9C;AAQA;AACA;AACA;AACA;;"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isInitialised, isSupported } from './common/index.mjs';
|
|
2
2
|
import { InitError, ElementError, SupportError } from './errors/index.mjs';
|
|
3
3
|
|
|
4
|
+
const _self = typeof globalThis !== 'undefined' ? globalThis : self;
|
|
4
5
|
class Component {
|
|
5
6
|
/**
|
|
6
7
|
* Returns the root element of the component
|
|
@@ -54,7 +55,7 @@ class Component {
|
|
|
54
55
|
/**
|
|
55
56
|
* @typedef {typeof Component & ChildClass} ChildClassConstructor
|
|
56
57
|
*/
|
|
57
|
-
Component.elementType = HTMLElement;
|
|
58
|
+
Component.elementType = _self.HTMLElement;
|
|
58
59
|
|
|
59
60
|
export { Component };
|
|
60
61
|
//# sourceMappingURL=component.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.mjs","sources":["../../src/govuk/component.mjs"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"component.mjs","sources":["../../src/govuk/component.mjs"],"sourcesContent":["/* eslint-disable es-x/no-global-this */\n\nimport { isInitialised, isSupported } from './common/index.mjs'\nimport { ElementError, InitError, SupportError } from './errors/index.mjs'\n\nconst _self =\n typeof globalThis !== 'undefined'\n ? globalThis // Modern browsers, Node.js\n : self // Old browsers, web workers\n\n/**\n * Base Component class\n *\n * Centralises the behaviours shared by our components\n *\n * @virtual\n * @template {Element} [RootElementType=HTMLElement]\n */\nexport class Component {\n /**\n * @type {typeof Element}\n */\n static elementType = _self.HTMLElement\n\n // allows Typescript user to work around the lack of types\n // in GOVUKFrontend package, Typescript is not aware of $root\n // in components that extend GOVUKFrontendComponent\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\n /**\n * @protected\n * @type {RootElementType}\n */\n _$root\n\n /**\n * Constructs a new component, validating that GOV.UK Frontend is supported\n *\n * @internal\n * @param {Element | null} [$root] - HTML element to use for component\n */\n constructor($root) {\n const childConstructor = /** @type {ChildClassConstructor} */ (\n this.constructor\n )\n\n // TypeScript does not enforce that inheriting classes will define a `moduleName`\n // (even if we add a `@virtual` `static moduleName` property to this class).\n // While we trust users to do this correctly, we do a little check to provide them\n // a helpful error message.\n //\n // After this, we'll be sure that `childConstructor` has a `moduleName`\n // as expected of the `ChildClassConstructor` we've cast `this.constructor` to.\n if (typeof childConstructor.moduleName !== 'string') {\n throw new InitError(`\\`moduleName\\` not defined in component`)\n }\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 = /** @type {RootElementType} */ ($root)\n }\n\n childConstructor.checkSupport()\n\n this.checkInitialised()\n\n const moduleName = childConstructor.moduleName\n\n this.$root.setAttribute(`data-${moduleName}-init`, '')\n }\n\n /**\n * Validates whether component is already initialised\n *\n * @private\n * @throws {InitError} when component is already initialised\n */\n checkInitialised() {\n const constructor = /** @type {ChildClassConstructor} */ (this.constructor)\n const moduleName = constructor.moduleName\n\n if (moduleName && isInitialised(this.$root, moduleName)) {\n throw new InitError(constructor)\n }\n }\n\n /**\n * Validates whether components are supported\n *\n * @throws {SupportError} when the components are not supported\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 */\n"],"names":["_self","globalThis","self","Component","$root","_$root","constructor","childConstructor","moduleName","InitError","elementType","ElementError","element","component","identifier","expectedType","name","checkSupport","checkInitialised","setAttribute","isInitialised","isSupported","SupportError","HTMLElement"],"mappings":";;;AAKA,MAAMA,KAAK,GACT,OAAOC,UAAU,KAAK,WAAW,GAC7BA,UAAU,GACVC,IAAI;AAUH,MAAMC,SAAS,CAAC;AASrB;AACF;AACA;AACA;AACA;AACA;EACE,IAAIC,KAAKA,GAAG;IACV,OAAO,IAAI,CAACC,MAAM;AACpB,EAAA;EAcAC,WAAWA,CAACF,KAAK,EAAE;AAAA,IAAA,IAAA,CARnBC,MAAM,GAAA,MAAA;AASJ,IAAA,MAAME,gBAAgB,GACpB,IAAI,CAACD,WACN;AASD,IAAA,IAAI,OAAOC,gBAAgB,CAACC,UAAU,KAAK,QAAQ,EAAE;AACnD,MAAA,MAAM,IAAIC,SAAS,CAAC,CAAA,uCAAA,CAAyC,CAAC;AAChE,IAAA;AAEA,IAAA,IAAI,EAAEL,KAAK,YAAYG,gBAAgB,CAACG,WAAW,CAAC,EAAE;MACpD,MAAM,IAAIC,YAAY,CAAC;AACrBC,QAAAA,OAAO,EAAER,KAAK;AACdS,QAAAA,SAAS,EAAEN,gBAAgB;AAC3BO,QAAAA,UAAU,EAAE,wBAAwB;AACpCC,QAAAA,YAAY,EAAER,gBAAgB,CAACG,WAAW,CAACM;AAC7C,OAAC,CAAC;AACJ,IAAA,CAAC,MAAM;MACL,IAAI,CAACX,MAAM,GAAmCD,KAAM;AACtD,IAAA;IAEAG,gBAAgB,CAACU,YAAY,EAAE;IAE/B,IAAI,CAACC,gBAAgB,EAAE;AAEvB,IAAA,MAAMV,UAAU,GAAGD,gBAAgB,CAACC,UAAU;IAE9C,IAAI,CAACJ,KAAK,CAACe,YAAY,CAAC,QAAQX,UAAU,CAAA,KAAA,CAAO,EAAE,EAAE,CAAC;AACxD,EAAA;AAQAU,EAAAA,gBAAgBA,GAAG;AACjB,IAAA,MAAMZ,WAAW,GAAyC,IAAI,CAACA,WAAY;AAC3E,IAAA,MAAME,UAAU,GAAGF,WAAW,CAACE,UAAU;IAEzC,IAAIA,UAAU,IAAIY,aAAa,CAAC,IAAI,CAAChB,KAAK,EAAEI,UAAU,CAAC,EAAE;AACvD,MAAA,MAAM,IAAIC,SAAS,CAACH,WAAW,CAAC;AAClC,IAAA;AACF,EAAA;EAOA,OAAOW,YAAYA,GAAG;AACpB,IAAA,IAAI,CAACI,WAAW,EAAE,EAAE;MAClB,MAAM,IAAIC,YAAY,EAAE;AAC1B,IAAA;AACF,EAAA;AACF;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AArGanB,SAAS,CAIbO,WAAW,GAAGV,KAAK,CAACuB,WAAW;;"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
@import "error-message";
|
|
11
11
|
@import "error-summary";
|
|
12
12
|
@import "exit-this-page";
|
|
13
|
+
@import "feedback";
|
|
13
14
|
@import "fieldset";
|
|
14
15
|
@import "file-upload";
|
|
15
16
|
@import "footer";
|
|
@@ -19,6 +20,7 @@
|
|
|
19
20
|
@import "input";
|
|
20
21
|
@import "inset-text";
|
|
21
22
|
@import "label";
|
|
23
|
+
@import "language-navigation";
|
|
22
24
|
@import "notification-banner";
|
|
23
25
|
@import "pagination";
|
|
24
26
|
@import "panel";
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
@use "error-message";
|
|
11
11
|
@use "error-summary";
|
|
12
12
|
@use "exit-this-page";
|
|
13
|
+
@use "feedback";
|
|
13
14
|
@use "fieldset";
|
|
14
15
|
@use "file-upload";
|
|
15
16
|
@use "footer";
|
|
@@ -19,6 +20,7 @@
|
|
|
19
20
|
@use "input";
|
|
20
21
|
@use "inset-text";
|
|
21
22
|
@use "label";
|
|
23
|
+
@use "language-navigation";
|
|
22
24
|
@use "notification-banner";
|
|
23
25
|
@use "pagination";
|
|
24
26
|
@use "panel";
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
function isObject(option) {
|
|
30
30
|
return !!option && typeof option === 'object' && !isArray(option);
|
|
31
31
|
}
|
|
32
|
+
function isScope($scope) {
|
|
33
|
+
return !!$scope && ($scope instanceof Element || $scope instanceof Document);
|
|
34
|
+
}
|
|
32
35
|
function formatErrorMessage(Component, message) {
|
|
33
36
|
return `${Component.moduleName}: ${message}`;
|
|
34
37
|
}
|
|
@@ -47,11 +50,14 @@
|
|
|
47
50
|
/**
|
|
48
51
|
* Checks if GOV.UK Frontend is supported on this page
|
|
49
52
|
*
|
|
50
|
-
* @param {
|
|
53
|
+
* @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
|
|
51
54
|
*/
|
|
52
|
-
constructor(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
constructor(scopeOrMessage = document.body) {
|
|
56
|
+
let 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';
|
|
57
|
+
if (!isScope(scopeOrMessage)) {
|
|
58
|
+
supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
|
|
59
|
+
}
|
|
60
|
+
super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
|
|
55
61
|
this.name = 'SupportError';
|
|
56
62
|
}
|
|
57
63
|
}
|
|
@@ -92,6 +98,7 @@
|
|
|
92
98
|
* @import { ComponentWithModuleName } from '../common/index.mjs'
|
|
93
99
|
*/
|
|
94
100
|
|
|
101
|
+
const _self = typeof globalThis !== 'undefined' ? globalThis : self;
|
|
95
102
|
class Component {
|
|
96
103
|
/**
|
|
97
104
|
* Returns the root element of the component
|
|
@@ -145,7 +152,7 @@
|
|
|
145
152
|
/**
|
|
146
153
|
* @typedef {typeof Component & ChildClass} ChildClassConstructor
|
|
147
154
|
*/
|
|
148
|
-
Component.elementType = HTMLElement;
|
|
155
|
+
Component.elementType = _self.HTMLElement;
|
|
149
156
|
|
|
150
157
|
const configOverride = Symbol.for('configOverride');
|
|
151
158
|
class ConfigurableComponent extends Component {
|
|
@@ -170,10 +177,14 @@
|
|
|
170
177
|
throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
|
|
171
178
|
}
|
|
172
179
|
const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
|
|
173
|
-
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}
|
|
180
|
+
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
|
|
181
|
+
this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
|
|
174
182
|
}
|
|
175
183
|
}
|
|
176
184
|
function normaliseString(value, property) {
|
|
185
|
+
if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
177
188
|
const trimmedValue = value ? value.trim() : '';
|
|
178
189
|
let output;
|
|
179
190
|
let outputType = property == null ? void 0 : property.type;
|
|
@@ -293,6 +304,17 @@
|
|
|
293
304
|
* @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
|
|
294
305
|
*/
|
|
295
306
|
|
|
307
|
+
function createElement(tagName, attributes = {}, children = []) {
|
|
308
|
+
const $element = document.createElement(tagName);
|
|
309
|
+
Object.entries(attributes).forEach(([name, value]) => {
|
|
310
|
+
$element.setAttribute(name, value);
|
|
311
|
+
});
|
|
312
|
+
for (const child of children) {
|
|
313
|
+
$element.append(child);
|
|
314
|
+
}
|
|
315
|
+
return $element;
|
|
316
|
+
}
|
|
317
|
+
|
|
296
318
|
class I18n {
|
|
297
319
|
constructor(translations = {}, config = {}) {
|
|
298
320
|
var _config$locale;
|
|
@@ -384,24 +406,16 @@
|
|
|
384
406
|
constructor($root, config = {}) {
|
|
385
407
|
super($root, config);
|
|
386
408
|
this.i18n = void 0;
|
|
387
|
-
this.controlsClass = 'govuk-accordion__controls';
|
|
388
|
-
this.showAllClass = 'govuk-accordion__show-all';
|
|
389
|
-
this.showAllTextClass = 'govuk-accordion__show-all-text';
|
|
390
409
|
this.sectionClass = 'govuk-accordion__section';
|
|
391
|
-
this.
|
|
410
|
+
this.sectionExpandedModifier = 'govuk-accordion__section--expanded';
|
|
392
411
|
this.sectionButtonClass = 'govuk-accordion__section-button';
|
|
393
412
|
this.sectionHeaderClass = 'govuk-accordion__section-header';
|
|
394
413
|
this.sectionHeadingClass = 'govuk-accordion__section-heading';
|
|
395
|
-
this.sectionHeadingDividerClass = 'govuk-accordion__section-heading-divider';
|
|
396
414
|
this.sectionHeadingTextClass = 'govuk-accordion__section-heading-text';
|
|
397
|
-
this.
|
|
398
|
-
this.
|
|
399
|
-
this.
|
|
400
|
-
this.sectionShowHideTextClass = 'govuk-accordion__section-toggle-text';
|
|
401
|
-
this.upChevronIconClass = 'govuk-accordion-nav__chevron';
|
|
402
|
-
this.downChevronIconClass = 'govuk-accordion-nav__chevron--down';
|
|
415
|
+
this.sectionToggleTextClass = 'govuk-accordion__section-toggle-text';
|
|
416
|
+
this.iconClass = 'govuk-accordion-nav__chevron';
|
|
417
|
+
this.iconOpenModifier = 'govuk-accordion-nav__chevron--down';
|
|
403
418
|
this.sectionSummaryClass = 'govuk-accordion__section-summary';
|
|
404
|
-
this.sectionSummaryFocusClass = 'govuk-accordion__section-summary-focus';
|
|
405
419
|
this.sectionContentClass = 'govuk-accordion__section-content';
|
|
406
420
|
this.$sections = void 0;
|
|
407
421
|
this.$showAllButton = null;
|
|
@@ -421,19 +435,23 @@
|
|
|
421
435
|
this.updateShowAllButton(this.areAllSectionsOpen());
|
|
422
436
|
}
|
|
423
437
|
initControls() {
|
|
424
|
-
this.$showAllButton =
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
this.$showAllIcon
|
|
438
|
+
this.$showAllButton = createElement('button', {
|
|
439
|
+
type: 'button',
|
|
440
|
+
class: 'govuk-accordion__show-all',
|
|
441
|
+
'aria-expanded': 'false'
|
|
442
|
+
});
|
|
443
|
+
this.$showAllIcon = createElement('span', {
|
|
444
|
+
class: this.iconClass
|
|
445
|
+
});
|
|
430
446
|
this.$showAllButton.appendChild(this.$showAllIcon);
|
|
431
|
-
const $accordionControls =
|
|
432
|
-
|
|
447
|
+
const $accordionControls = createElement('div', {
|
|
448
|
+
class: 'govuk-accordion__controls'
|
|
449
|
+
});
|
|
433
450
|
$accordionControls.appendChild(this.$showAllButton);
|
|
434
451
|
this.$root.insertBefore($accordionControls, this.$root.firstChild);
|
|
435
|
-
this.$showAllText =
|
|
436
|
-
|
|
452
|
+
this.$showAllText = createElement('span', {
|
|
453
|
+
class: 'govuk-accordion__show-all-text'
|
|
454
|
+
});
|
|
437
455
|
this.$showAllButton.appendChild(this.$showAllText);
|
|
438
456
|
this.$showAllButton.addEventListener('click', () => this.onShowOrHideAllToggle());
|
|
439
457
|
if ('onbeforematch' in document) {
|
|
@@ -471,39 +489,45 @@
|
|
|
471
489
|
identifier: `Section button placeholder (\`<span class="${this.sectionButtonClass}">\`)`
|
|
472
490
|
});
|
|
473
491
|
}
|
|
474
|
-
const $button =
|
|
475
|
-
|
|
476
|
-
|
|
492
|
+
const $button = createElement('button', {
|
|
493
|
+
type: 'button',
|
|
494
|
+
'aria-controls': `${this.$root.id}-content-${index + 1}`
|
|
495
|
+
});
|
|
477
496
|
for (const attr of Array.from($span.attributes)) {
|
|
478
497
|
if (attr.name !== 'id') {
|
|
479
498
|
$button.setAttribute(attr.name, attr.value);
|
|
480
499
|
}
|
|
481
500
|
}
|
|
482
|
-
const $headingText =
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
$headingTextFocus
|
|
501
|
+
const $headingText = createElement('span', {
|
|
502
|
+
class: this.sectionHeadingTextClass,
|
|
503
|
+
id: $span.id
|
|
504
|
+
});
|
|
505
|
+
const $headingTextFocus = createElement('span', {
|
|
506
|
+
class: 'govuk-accordion__section-heading-text-focus'
|
|
507
|
+
});
|
|
487
508
|
$headingText.appendChild($headingTextFocus);
|
|
488
509
|
Array.from($span.childNodes).forEach($child => $headingTextFocus.appendChild($child));
|
|
489
|
-
const $showHideToggle =
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
$showHideToggleFocus
|
|
510
|
+
const $showHideToggle = createElement('span', {
|
|
511
|
+
class: 'govuk-accordion__section-toggle',
|
|
512
|
+
'data-nosnippet': ''
|
|
513
|
+
});
|
|
514
|
+
const $showHideToggleFocus = createElement('span', {
|
|
515
|
+
class: 'govuk-accordion__section-toggle-focus'
|
|
516
|
+
});
|
|
494
517
|
$showHideToggle.appendChild($showHideToggleFocus);
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
$showHideToggleFocus.appendChild(
|
|
499
|
-
|
|
500
|
-
|
|
518
|
+
$showHideToggleFocus.appendChild(createElement('span', {
|
|
519
|
+
class: this.iconClass
|
|
520
|
+
}));
|
|
521
|
+
$showHideToggleFocus.appendChild(createElement('span', {
|
|
522
|
+
class: this.sectionToggleTextClass
|
|
523
|
+
}));
|
|
501
524
|
$button.appendChild($headingText);
|
|
502
525
|
$button.appendChild(this.getButtonPunctuationEl());
|
|
503
526
|
if ($summary) {
|
|
504
|
-
const $summarySpan =
|
|
505
|
-
const $summarySpanFocus =
|
|
506
|
-
|
|
527
|
+
const $summarySpan = createElement('span');
|
|
528
|
+
const $summarySpanFocus = createElement('span', {
|
|
529
|
+
class: 'govuk-accordion__section-summary-focus'
|
|
530
|
+
});
|
|
507
531
|
$summarySpan.appendChild($summarySpanFocus);
|
|
508
532
|
for (const attr of Array.from($summary.attributes)) {
|
|
509
533
|
$summarySpan.setAttribute(attr.name, attr.value);
|
|
@@ -541,8 +565,8 @@
|
|
|
541
565
|
this.updateShowAllButton(nowExpanded);
|
|
542
566
|
}
|
|
543
567
|
setExpanded(expanded, $section) {
|
|
544
|
-
const $showHideIcon = $section.querySelector(`.${this.
|
|
545
|
-
const $showHideText = $section.querySelector(`.${this.
|
|
568
|
+
const $showHideIcon = $section.querySelector(`.${this.iconClass}`);
|
|
569
|
+
const $showHideText = $section.querySelector(`.${this.sectionToggleTextClass}`);
|
|
546
570
|
const $button = $section.querySelector(`.${this.sectionButtonClass}`);
|
|
547
571
|
const $content = $section.querySelector(`.${this.sectionContentClass}`);
|
|
548
572
|
if (!$content) {
|
|
@@ -571,17 +595,17 @@
|
|
|
571
595
|
$button.setAttribute('aria-label', ariaLabelParts.join(' , '));
|
|
572
596
|
if (expanded) {
|
|
573
597
|
$content.removeAttribute('hidden');
|
|
574
|
-
$section.classList.add(this.
|
|
575
|
-
$showHideIcon.classList.remove(this.
|
|
598
|
+
$section.classList.add(this.sectionExpandedModifier);
|
|
599
|
+
$showHideIcon.classList.remove(this.iconOpenModifier);
|
|
576
600
|
} else {
|
|
577
601
|
$content.setAttribute('hidden', 'until-found');
|
|
578
|
-
$section.classList.remove(this.
|
|
579
|
-
$showHideIcon.classList.add(this.
|
|
602
|
+
$section.classList.remove(this.sectionExpandedModifier);
|
|
603
|
+
$showHideIcon.classList.add(this.iconOpenModifier);
|
|
580
604
|
}
|
|
581
605
|
this.updateShowAllButton(this.areAllSectionsOpen());
|
|
582
606
|
}
|
|
583
607
|
isExpanded($section) {
|
|
584
|
-
return $section.classList.contains(this.
|
|
608
|
+
return $section.classList.contains(this.sectionExpandedModifier);
|
|
585
609
|
}
|
|
586
610
|
areAllSectionsOpen() {
|
|
587
611
|
return Array.from(this.$sections).every($section => this.isExpanded($section));
|
|
@@ -592,7 +616,7 @@
|
|
|
592
616
|
}
|
|
593
617
|
this.$showAllButton.setAttribute('aria-expanded', expanded.toString());
|
|
594
618
|
this.$showAllText.textContent = expanded ? this.i18n.t('hideAllSections') : this.i18n.t('showAllSections');
|
|
595
|
-
this.$showAllIcon.classList.toggle(this.
|
|
619
|
+
this.$showAllIcon.classList.toggle(this.iconOpenModifier, !expanded);
|
|
596
620
|
}
|
|
597
621
|
|
|
598
622
|
/**
|
|
@@ -635,10 +659,11 @@
|
|
|
635
659
|
}
|
|
636
660
|
}
|
|
637
661
|
getButtonPunctuationEl() {
|
|
638
|
-
const $
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
662
|
+
const $element = createElement('span', {
|
|
663
|
+
class: 'govuk-visually-hidden govuk-accordion__section-heading-divider'
|
|
664
|
+
});
|
|
665
|
+
$element.textContent = ', ';
|
|
666
|
+
return $element;
|
|
642
667
|
}
|
|
643
668
|
}
|
|
644
669
|
|