Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v5.4.0 #4987

Merged
merged 1 commit into from
May 17, 2024
Merged

Release v5.4.0 #4987

merged 1 commit into from
May 17, 2024

Conversation

patrickpatrickpatrick
Copy link
Contributor

@patrickpatrickpatrick patrickpatrickpatrick commented May 17, 2024

To install this version with npm, run npm install govuk-frontend@5.4.0. You can also find more information about how to stay up to date in our documentation.

This release includes new features to help you include only the components your service uses. Doing this can help reduce the size of the JavaScript and CSS files sent to users, improving their experience.

New features

Create individual components with createAll

We've added a new createAll function that lets you initialise specific components in the same way that initAll does.

The createAll function will:

  • find all elements in the page with the corresponding data-module attribute
  • instantiate a component object for each element
  • catch errors and log them in the console
  • return an array of all the successfully instantiated component objects.
import { createAll, Button, Checkboxes } from 'govuk-frontend'

createAll(Button)
createAll(Checkboxes)

You can also pass a config object and a scope within which to search for elements.

You can find out more about how to use the createAll function in our documentation.

This change was introduced in pull request #4975: Add createAll function to initialise individual components.

Use tabular numbers easily with govuk-!-font-tabular-numbers

We've added a new override class for tabular number styling: govuk-!-font-tabular-numbers.

Using tabular numbers can make it easier for users to read numbers intended for comparison to one another, or for numbers that dynamically update.

It was previously only possible to use tabular numbers by using the govuk-font-tabular-numbers Sass mixin.

This change was introduced in pull request #4973: Add override class for tabular numbers.

Deprecated features

Importing layers using all files

You'll see a warning when compiling your Sass if you import any of our layers using the all file. Importing using the all files is deprecated, and we’ll remove them in the next major release.

Update your import statements to refer to the index file for each layer rather than all:

@import "node_modules/govuk-frontend/dist/govuk/base";
@import "node_modules/govuk-frontend/dist/govuk/core/index";
@import "node_modules/govuk-frontend/dist/govuk/objects/index";
@import "node_modules/govuk-frontend/dist/govuk/components/index";
@import "node_modules/govuk-frontend/dist/govuk/utilities/index";
@import "node_modules/govuk-frontend/dist/govuk/overrides/index";

You do not need /index at the end of each import path if you’re using Dart Sass, LibSass 3.6.0 or higher, or Ruby Sass 3.6.0 or higher.

This change was introduced in pull request #4955: Rename all files to index for our Sass entry points.

Fixes

We've made fixes to GOV.UK Frontend in the following pull requests:

Copy link

github-actions bot commented May 17, 2024

JavaScript changes to GitHub release

diff --git a/dist/govuk-frontend-5.3.1.min.js b/dist/govuk-frontend-5.4.0.min.js
index a2d459b47..7c8495726 100644
--- a/dist/govuk-frontend-5.3.1.min.js
+++ b/dist/govuk-frontend-5.4.0.min.js
@@ -1,44 +1,44 @@
-const version = "5.3.1";
+const version = "5.4.0";
 
 function normaliseString(e, t) {
-    const s = e ? e.trim() : "";
-    let n, i = null == t ? void 0 : t.type;
-    switch (i || (["true", "false"].includes(s) && (i = "boolean"), s.length > 0 && isFinite(Number(s)) && (i = "number")), i) {
+    const n = e ? e.trim() : "";
+    let s, i = null == t ? void 0 : t.type;
+    switch (i || (["true", "false"].includes(n) && (i = "boolean"), n.length > 0 && isFinite(Number(n)) && (i = "number")), i) {
         case "boolean":
-            n = "true" === s;
+            s = "true" === n;
             break;
         case "number":
-            n = Number(s);
+            s = Number(n);
             break;
         default:
-            n = e
+            s = e
     }
-    return n
+    return s
 }
 
 function mergeConfigs(...e) {
     const t = {};
-    for (const s of e)
-        for (const e of Object.keys(s)) {
-            const n = t[e],
-                i = s[e];
-            isObject(n) && isObject(i) ? t[e] = mergeConfigs(n, i) : t[e] = i
+    for (const n of e)
+        for (const e of Object.keys(n)) {
+            const s = t[e],
+                i = n[e];
+            isObject(s) && isObject(i) ? t[e] = mergeConfigs(s, i) : t[e] = i
         }
     return t
 }
 
-function extractConfigByNamespace(e, t, s) {
-    const n = e.schema.properties[s];
-    if ("object" !== (null == n ? void 0 : n.type)) return;
+function extractConfigByNamespace(e, t, n) {
+    const s = e.schema.properties[n];
+    if ("object" !== (null == s ? void 0 : s.type)) return;
     const i = {
-        [s]: {}
+        [n]: {}
     };
     for (const [o, r] of Object.entries(t)) {
         let e = i;
         const t = o.split(".");
-        for (const [n, i] of t.entries()) "object" == typeof e && (n < t.length - 1 ? (isObject(e[i]) || (e[i] = {}), e = e[i]) : o !== s && (e[i] = normaliseString(r)))
+        for (const [s, i] of t.entries()) "object" == typeof e && (s < t.length - 1 ? (isObject(e[i]) || (e[i] = {}), e = e[i]) : o !== n && (e[i] = normaliseString(r)))
     }
-    return i[s]
+    return i[n]
 }
 
 function getFragmentFromUrl(e) {
@@ -54,20 +54,20 @@ function getBreakpoint(e) {
 }
 
 function setFocus(e, t = {}) {
-    var s;
-    const n = e.getAttribute("tabindex");
+    var n;
+    const s = e.getAttribute("tabindex");
 
     function onBlur() {
-        var s;
-        null == (s = t.onBlur) || s.call(e), n || e.removeAttribute("tabindex")
+        var n;
+        null == (n = t.onBlur) || n.call(e), s || e.removeAttribute("tabindex")
     }
-    n || e.setAttribute("tabindex", "-1"), e.addEventListener("focus", (function() {
+    s || e.setAttribute("tabindex", "-1"), e.addEventListener("focus", (function() {
         e.addEventListener("blur", onBlur, {
             once: !0
         })
     }), {
         once: !0
-    }), null == (s = t.onBeforeFocus) || s.call(e), e.focus()
+    }), null == (n = t.onBeforeFocus) || n.call(e), e.focus()
 }
 
 function isSupported(e = document.body) {
@@ -81,9 +81,9 @@ function isObject(e) {
 }
 
 function normaliseDataset(e, t) {
-    const s = {};
-    for (const [n, i] of Object.entries(e.schema.properties)) n in t && (s[n] = normaliseString(t[n], i)), "object" === (null == i ? void 0 : i.type) && (s[n] = extractConfigByNamespace(e, t, n));
-    return s
+    const n = {};
+    for (const [s, i] of Object.entries(e.schema.properties)) s in t && (n[s] = normaliseString(t[s], i)), "object" === (null == i ? void 0 : i.type) && (n[s] = extractConfigByNamespace(e, t, s));
+    return n
 }
 class GOVUKFrontendError extends Error {
     constructor(...e) {
@@ -106,12 +106,12 @@ class ElementError extends GOVUKFrontendError {
         let t = "string" == typeof e ? e : "";
         if ("object" == typeof e) {
             const {
-                componentName: s,
-                identifier: n,
+                componentName: n,
+                identifier: s,
                 element: i,
                 expectedType: o
             } = e;
-            t = `${s}: ${n}`, t += i ? ` is not of type ${null!=o?o:"HTMLElement"}` : " not found"
+            t = `${n}: ${s}`, t += i ? ` is not of type ${null!=o?o:"HTMLElement"}` : " not found"
         }
         super(t), this.name = "ElementError"
     }
@@ -126,31 +126,31 @@ class GOVUKFrontendComponent {
 }
 class I18n {
     constructor(e = {}, t = {}) {
-        var s;
-        this.translations = void 0, this.locale = void 0, this.translations = e, this.locale = null != (s = t.locale) ? s : document.documentElement.lang || "en"
+        var n;
+        this.translations = void 0, this.locale = void 0, this.translations = e, this.locale = null != (n = t.locale) ? n : document.documentElement.lang || "en"
     }
     t(e, t) {
         if (!e) throw new Error("i18n: lookup key missing");
-        let s = this.translations[e];
-        if ("number" == typeof(null == t ? void 0 : t.count) && "object" == typeof s) {
-            const n = s[this.getPluralSuffix(e, t.count)];
-            n && (s = n)
+        let n = this.translations[e];
+        if ("number" == typeof(null == t ? void 0 : t.count) && "object" == typeof n) {
+            const s = n[this.getPluralSuffix(e, t.count)];
+            s && (n = s)
         }
-        if ("string" == typeof s) {
-            if (s.match(/%{(.\S+)}/)) {
+        if ("string" == typeof n) {
+            if (n.match(/%{(.\S+)}/)) {
                 if (!t) throw new Error("i18n: cannot replace placeholders in string if no option data provided");
-                return this.replacePlaceholders(s, t)
+                return this.replacePlaceholders(n, t)
             }
-            return s
+            return n
         }
         return e
     }
     replacePlaceholders(e, t) {
-        const s = Intl.NumberFormat.supportedLocalesOf(this.locale).length ? new Intl.NumberFormat(this.locale) : void 0;
-        return e.replace(/%{(.\S+)}/g, (function(e, n) {
-            if (Object.prototype.hasOwnProperty.call(t, n)) {
-                const e = t[n];
-                return !1 === e || "number" != typeof e && "string" != typeof e ? "" : "number" == typeof e ? s ? s.format(e) : `${e}` : e
+        const n = Intl.NumberFormat.supportedLocalesOf(this.locale).length ? new Intl.NumberFormat(this.locale) : void 0;
+        return e.replace(/%{(.\S+)}/g, (function(e, s) {
+            if (Object.prototype.hasOwnProperty.call(t, s)) {
+                const e = t[s];
+                return !1 === e || "number" != typeof e && "string" != typeof e ? "" : "number" == typeof e ? n ? n.format(e) : `${e}` : e
             }
             throw new Error(`i18n: no data found to replace ${e} placeholder in string`)
         }))
@@ -160,11 +160,11 @@ class I18n {
     }
     getPluralSuffix(e, t) {
         if (t = Number(t), !isFinite(t)) return "other";
-        const s = this.translations[e],
-            n = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(t) : this.selectPluralFormUsingFallbackRules(t);
-        if ("object" == typeof s) {
-            if (n in s) return n;
-            if ("other" in s) return console.warn(`i18n: Missing plural form ".${n}" for "${this.locale}" locale. Falling back to ".other".`), "other"
+        const n = this.translations[e],
+            s = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(t) : this.selectPluralFormUsingFallbackRules(t);
+        if ("object" == typeof n) {
+            if (s in n) return s;
+            if ("other" in n) return console.warn(`i18n: Missing plural form ".${s}" for "${this.locale}" locale. Falling back to ".other".`), "other"
         }
         throw new Error(`i18n: Plural form ".other" is required for "${this.locale}" locale`)
     }
@@ -176,8 +176,8 @@ class I18n {
     getPluralRulesForLocale() {
         const e = this.locale.split("-")[0];
         for (const t in I18n.pluralRulesMap) {
-            const s = I18n.pluralRulesMap[t];
-            if (s.includes(this.locale) || s.includes(e)) return t
+            const n = I18n.pluralRulesMap[t];
+            if (n.includes(this.locale) || n.includes(e)) return t
         }
     }
 }
@@ -199,27 +199,27 @@ I18n.pluralRulesMap = {
     irish: e => 1 === e ? "one" : 2 === e ? "two" : e >= 3 && e <= 6 ? "few" : e >= 7 && e <= 10 ? "many" : "other",
     russian(e) {
         const t = e % 100,
-            s = t % 10;
-        return 1 === s && 11 !== t ? "one" : s >= 2 && s <= 4 && !(t >= 12 && t <= 14) ? "few" : 0 === s || s >= 5 && s <= 9 || t >= 11 && t <= 14 ? "many" : "other"
+            n = t % 10;
+        return 1 === n && 11 !== t ? "one" : n >= 2 && n <= 4 && !(t >= 12 && t <= 14) ? "few" : 0 === n || n >= 5 && n <= 9 || t >= 11 && t <= 14 ? "many" : "other"
     },
     scottish: e => 1 === e || 11 === e ? "one" : 2 === e || 12 === e ? "two" : e >= 3 && e <= 10 || e >= 13 && e <= 19 ? "few" : "other",
     spanish: e => 1 === e ? "one" : e % 1e6 == 0 && 0 !== e ? "many" : "other",
     welsh: e => 0 === e ? "zero" : 1 === e ? "one" : 2 === e ? "two" : 3 === e ? "few" : 6 === e ? "many" : "other"
 };
 class Accordion extends GOVUKFrontendComponent {
-    constructor(t, s = {}) {
+    constructor(t, n = {}) {
         if (super(), this.$module = void 0, this.config = void 0, this.i18n = void 0, this.controlsClass = "govuk-accordion__controls", this.showAllClass = "govuk-accordion__show-all", this.showAllTextClass = "govuk-accordion__show-all-text", this.sectionClass = "govuk-accordion__section", this.sectionExpandedClass = "govuk-accordion__section--expanded", this.sectionButtonClass = "govuk-accordion__section-button", this.sectionHeaderClass = "govuk-accordion__section-header", this.sectionHeadingClass = "govuk-accordion__section-heading", this.sectionHeadingDividerClass = "govuk-accordion__section-heading-divider", this.sectionHeadingTextClass = "govuk-accordion__section-heading-text", this.sectionHeadingTextFocusClass = "govuk-accordion__section-heading-text-focus", this.sectionShowHideToggleClass = "govuk-accordion__section-toggle", this.sectionShowHideToggleFocusClass = "govuk-accordion__section-toggle-focus", this.sectionShowHideTextClass = "govuk-accordion__section-toggle-text", this.upChevronIconClass = "govuk-accordion-nav__chevron", this.downChevronIconClass = "govuk-accordion-nav__chevron--down", this.sectionSummaryClass = "govuk-accordion__section-summary", this.sectionSummaryFocusClass = "govuk-accordion__section-summary-focus", this.sectionContentClass = "govuk-accordion__section-content", this.$sections = void 0, this.browserSupportsSessionStorage = !1, this.$showAllButton = null, this.$showAllIcon = null, this.$showAllText = null, !(t instanceof HTMLElement)) throw new ElementError({
             componentName: "Accordion",
             element: t,
             identifier: "Root element (`$module`)"
         });
-        this.$module = t, this.config = mergeConfigs(Accordion.defaults, s, normaliseDataset(Accordion, t.dataset)), this.i18n = new I18n(this.config.i18n);
-        const n = this.$module.querySelectorAll(`.${this.sectionClass}`);
-        if (!n.length) throw new ElementError({
+        this.$module = t, this.config = mergeConfigs(Accordion.defaults, n, normaliseDataset(Accordion, t.dataset)), this.i18n = new I18n(this.config.i18n);
+        const s = this.$module.querySelectorAll(`.${this.sectionClass}`);
+        if (!s.length) throw new ElementError({
             componentName: "Accordion",
             identifier: `Sections (\`<div class="${this.sectionClass}">\`)`
         });
-        this.$sections = n, this.browserSupportsSessionStorage = e.checkForSessionStorage(), this.initControls(), this.initSectionHeaders();
+        this.$sections = s, this.browserSupportsSessionStorage = e.checkForSessionStorage(), this.initControls(), this.initSectionHeaders();
         const i = this.checkIfAllSectionsOpen();
         this.updateShowAllButton(i)
     }
@@ -230,33 +230,33 @@ class Accordion extends GOVUKFrontendComponent {
     }
     initSectionHeaders() {
         this.$sections.forEach(((e, t) => {
-            const s = e.querySelector(`.${this.sectionHeaderClass}`);
-            if (!s) throw new ElementError({
+            const n = e.querySelector(`.${this.sectionHeaderClass}`);
+            if (!n) throw new ElementError({
                 componentName: "Accordion",
                 identifier: `Section headers (\`<div class="${this.sectionHeaderClass}">\`)`
             });
-            this.constructHeaderMarkup(s, t), this.setExpanded(this.isExpanded(e), e), s.addEventListener("click", (() => this.onSectionToggle(e))), this.setInitialState(e)
+            this.constructHeaderMarkup(n, t), this.setExpanded(this.isExpanded(e), e), n.addEventListener("click", (() => this.onSectionToggle(e))), this.setInitialState(e)
         }))
     }
     constructHeaderMarkup(e, t) {
-        const s = e.querySelector(`.${this.sectionButtonClass}`),
-            n = e.querySelector(`.${this.sectionHeadingClass}`),
+        const n = e.querySelector(`.${this.sectionButtonClass}`),
+            s = e.querySelector(`.${this.sectionHeadingClass}`),
             i = e.querySelector(`.${this.sectionSummaryClass}`);
-        if (!n) throw new ElementError({
+        if (!s) throw new ElementError({
             componentName: "Accordion",
             identifier: `Section heading (\`.${this.sectionHeadingClass}\`)`
         });
-        if (!s) throw new ElementError({
+        if (!n) throw new ElementError({
             componentName: "Accordion",
             identifier: `Section button placeholder (\`<span class="${this.sectionButtonClass}">\`)`
         });
         const o = document.createElement("button");
         o.setAttribute("type", "button"), o.setAttribute("aria-controls", `${this.$module.id}-content-${t+1}`);
-        for (const d of Array.from(s.attributes)) "id" !== d.nodeName && o.setAttribute(d.nodeName, `${d.nodeValue}`);
+        for (const d of Array.from(n.attributes)) "id" !== d.nodeName && o.setAttribute(d.nodeName, `${d.nodeValue}`);
         const r = document.createElement("span");
-        r.classList.add(this.sectionHeadingTextClass), r.id = s.id;
+        r.classList.add(this.sectionHeadingTextClass), r.id = n.id;
         const a = document.createElement("span");
-        a.classList.add(this.sectionHeadingTextFocusClass), r.appendChild(a), a.innerHTML = s.innerHTML;
+        a.classList.add(this.sectionHeadingTextFocusClass), r.appendChild(a), a.innerHTML = n.innerHTML;
         const l = document.createElement("span");
         l.classList.add(this.sectionShowHideToggleClass), l.setAttribute("data-nosnippet", "");
         const c = document.createElement("span");
@@ -267,16 +267,16 @@ class Accordion extends GOVUKFrontendComponent {
             const e = document.createElement("span"),
                 t = document.createElement("span");
             t.classList.add(this.sectionSummaryFocusClass), e.appendChild(t);
-            for (const s of Array.from(i.attributes)) e.setAttribute(s.nodeName, `${s.nodeValue}`);
+            for (const n of Array.from(i.attributes)) e.setAttribute(n.nodeName, `${n.nodeValue}`);
             t.innerHTML = i.innerHTML, i.parentNode.replaceChild(e, i), o.appendChild(e), o.appendChild(this.getButtonPunctuationEl())
         }
-        o.appendChild(l), n.removeChild(s), n.appendChild(o)
+        o.appendChild(l), s.removeChild(n), s.appendChild(o)
     }
     onBeforeMatch(e) {
         const t = e.target;
         if (!(t instanceof Element)) return;
-        const s = t.closest(`.${this.sectionClass}`);
-        s && this.setExpanded(!0, s)
+        const n = t.closest(`.${this.sectionClass}`);
+        n && this.setExpanded(!0, n)
     }
     onSectionToggle(e) {
         const t = this.isExpanded(e);
@@ -289,24 +289,24 @@ class Accordion extends GOVUKFrontendComponent {
         })), this.updateShowAllButton(e)
     }
     setExpanded(e, t) {
-        const s = t.querySelector(`.${this.upChevronIconClass}`),
-            n = t.querySelector(`.${this.sectionShowHideTextClass}`),
+        const n = t.querySelector(`.${this.upChevronIconClass}`),
+            s = t.querySelector(`.${this.sectionShowHideTextClass}`),
             i = t.querySelector(`.${this.sectionButtonClass}`),
             o = t.querySelector(`.${this.sectionContentClass}`);
         if (!o) throw new ElementError({
             componentName: "Accordion",
             identifier: `Section content (\`<div class="${this.sectionContentClass}">\`)`
         });
-        if (!s || !n || !i) return;
+        if (!n || !s || !i) return;
         const r = e ? this.i18n.t("hideSection") : this.i18n.t("showSection");
-        n.textContent = r, i.setAttribute("aria-expanded", `${e}`);
+        s.textContent = r, i.setAttribute("aria-expanded", `${e}`);
         const a = [],
             l = t.querySelector(`.${this.sectionHeadingTextClass}`);
         l && a.push(`${l.textContent}`.trim());
         const c = t.querySelector(`.${this.sectionSummaryClass}`);
         c && a.push(`${c.textContent}`.trim());
         const h = e ? this.i18n.t("hideSectionAriaLabel") : this.i18n.t("showSectionAriaLabel");
-        a.push(h), i.setAttribute("aria-label", a.join(" , ")), e ? (o.removeAttribute("hidden"), t.classList.add(this.sectionExpandedClass), s.classList.remove(this.downChevronIconClass)) : (o.setAttribute("hidden", "until-found"), t.classList.remove(this.sectionExpandedClass), s.classList.add(this.downChevronIconClass));
+        a.push(h), i.setAttribute("aria-label", a.join(" , ")), e ? (o.removeAttribute("hidden"), t.classList.add(this.sectionExpandedClass), n.classList.remove(this.downChevronIconClass)) : (o.setAttribute("hidden", "until-found"), t.classList.remove(this.sectionExpandedClass), n.classList.add(this.downChevronIconClass));
         const u = this.checkIfAllSectionsOpen();
         this.updateShowAllButton(u)
     }
@@ -324,8 +324,8 @@ class Accordion extends GOVUKFrontendComponent {
             const t = e.querySelector(`.${this.sectionButtonClass}`);
             if (t) {
                 const e = t.getAttribute("aria-controls"),
-                    s = t.getAttribute("aria-expanded");
-                e && s && window.sessionStorage.setItem(e, s)
+                    n = t.getAttribute("aria-expanded");
+                e && n && window.sessionStorage.setItem(e, n)
             }
         }
     }
@@ -333,9 +333,9 @@ class Accordion extends GOVUKFrontendComponent {
         if (this.browserSupportsSessionStorage && this.config.rememberExpanded) {
             const t = e.querySelector(`.${this.sectionButtonClass}`);
             if (t) {
-                const s = t.getAttribute("aria-controls"),
-                    n = s ? window.sessionStorage.getItem(s) : null;
-                null !== n && this.setExpanded("true" === n, e)
+                const n = t.getAttribute("aria-controls"),
+                    s = n ? window.sessionStorage.getItem(n) : null;
+                null !== s && this.setExpanded("true" === s, e)
             }
         }
     }
@@ -370,7 +370,7 @@ const e = {
         let t;
         try {
             return window.sessionStorage.setItem(e, e), t = window.sessionStorage.getItem(e) === e.toString(), window.sessionStorage.removeItem(e), t
-        } catch (s) {
+        } catch (n) {
             return !1
         }
     }
@@ -396,8 +396,8 @@ class Button extends GOVUKFrontendComponent {
 }
 
 function closestAttributeValue(e, t) {
-    const s = e.closest(`[${t}]`);
-    return s ? s.getAttribute(t) : null
+    const n = e.closest(`[${t}]`);
+    return n ? n.getAttribute(t) : null
 }
 Button.moduleName = "govuk-button", Button.defaults = Object.freeze({
     preventDoubleClick: !1
@@ -410,7 +410,7 @@ Button.moduleName = "govuk-button", Button.defaults = Object.freeze({
 });
 class CharacterCount extends GOVUKFrontendComponent {
     constructor(e, t = {}) {
-        var s, n;
+        var n, s;
         if (super(), this.$module = void 0, this.$textarea = void 0, this.$visibleCountMessage = void 0, this.$screenReaderCountMessage = void 0, this.lastInputTimestamp = null, this.lastInputValue = "", this.valueChecker = null, this.config = void 0, this.i18n = void 0, this.maxLength = void 0, !(e instanceof HTMLElement)) throw new ElementError({
             componentName: "Character count",
             element: e,
@@ -430,24 +430,24 @@ class CharacterCount extends GOVUKFrontendComponent {
             maxwords: void 0
         }), this.config = mergeConfigs(CharacterCount.defaults, t, r, o);
         const a = function(e, t) {
-            const s = [];
-            for (const [n, i] of Object.entries(e)) {
+            const n = [];
+            for (const [s, i] of Object.entries(e)) {
                 const e = [];
                 if (Array.isArray(i)) {
                     for (const {
-                            required: s,
-                            errorMessage: n
+                            required: n,
+                            errorMessage: s
                         }
-                        of i) s.every((e => !!t[e])) || e.push(n);
-                    "anyOf" !== n || i.length - e.length >= 1 || s.push(...e)
+                        of i) n.every((e => !!t[e])) || e.push(s);
+                    "anyOf" !== s || i.length - e.length >= 1 || n.push(...e)
                 }
             }
-            return s
+            return n
         }(CharacterCount.schema, this.config);
         if (a[0]) throw new ConfigError(`Character count: ${a[0]}`);
         this.i18n = new I18n(this.config.i18n, {
             locale: closestAttributeValue(e, "lang")
-        }), this.maxLength = null != (s = null != (n = this.config.maxwords) ? n : this.config.maxlength) ? s : 1 / 0, this.$module = e, this.$textarea = i;
+        }), this.maxLength = null != (n = null != (s = this.config.maxwords) ? s : this.config.maxlength) ? n : 1 / 0, this.$module = e, this.$textarea = i;
         const l = `${this.$textarea.id}-info`,
             c = document.getElementById(l);
         if (!c) throw new ElementError({
@@ -504,8 +504,8 @@ class CharacterCount extends GOVUKFrontendComponent {
     }
     formatCountMessage(e, t) {
         if (0 === e) return this.i18n.t(`${t}AtLimit`);
-        const s = e < 0 ? "OverLimit" : "UnderLimit";
-        return this.i18n.t(`${t}${s}`, {
+        const n = e < 0 ? "OverLimit" : "UnderLimit";
+        return this.i18n.t(`${t}${n}`, {
             count: Math.abs(e)
         })
     }
@@ -592,10 +592,10 @@ class Checkboxes extends GOVUKFrontendComponent {
     syncConditionalRevealWithInputState(e) {
         const t = e.getAttribute("aria-controls");
         if (!t) return;
-        const s = document.getElementById(t);
-        if (null != s && s.classList.contains("govuk-checkboxes__conditional")) {
+        const n = document.getElementById(t);
+        if (null != n && n.classList.contains("govuk-checkboxes__conditional")) {
             const t = e.checked;
-            e.setAttribute("aria-expanded", t.toString()), s.classList.toggle("govuk-checkboxes__conditional--hidden", !t)
+            e.setAttribute("aria-expanded", t.toString()), n.classList.toggle("govuk-checkboxes__conditional--hidden", !t)
         }
     }
     unCheckAllInputsExcept(e) {
@@ -633,25 +633,25 @@ class ErrorSummary extends GOVUKFrontendComponent {
         if (!(e instanceof HTMLAnchorElement)) return !1;
         const t = getFragmentFromUrl(e.href);
         if (!t) return !1;
-        const s = document.getElementById(t);
-        if (!s) return !1;
-        const n = this.getAssociatedLegendOrLabel(s);
-        return !!n && (n.scrollIntoView(), s.focus({
+        const n = document.getElementById(t);
+        if (!n) return !1;
+        const s = this.getAssociatedLegendOrLabel(n);
+        return !!s && (s.scrollIntoView(), n.focus({
             preventScroll: !0
         }), !0)
     }
     getAssociatedLegendOrLabel(e) {
         var t;
-        const s = e.closest("fieldset");
-        if (s) {
-            const t = s.getElementsByTagName("legend");
+        const n = e.closest("fieldset");
+        if (n) {
+            const t = n.getElementsByTagName("legend");
             if (t.length) {
-                const s = t[0];
-                if (e instanceof HTMLInputElement && ("checkbox" === e.type || "radio" === e.type)) return s;
-                const n = s.getBoundingClientRect().top,
+                const n = t[0];
+                if (e instanceof HTMLInputElement && ("checkbox" === e.type || "radio" === e.type)) return n;
+                const s = n.getBoundingClientRect().top,
                     i = e.getBoundingClientRect();
                 if (i.height && window.innerHeight) {
-                    if (i.top + i.height - n < window.innerHeight / 2) return s
+                    if (i.top + i.height - s < window.innerHeight / 2) return n
                 }
             }
         }
@@ -674,16 +674,16 @@ class ExitThisPage extends GOVUKFrontendComponent {
             element: e,
             identifier: "Root element (`$module`)"
         });
-        const s = e.querySelector(".govuk-exit-this-page__button");
-        if (!(s instanceof HTMLAnchorElement)) throw new ElementError({
+        const n = e.querySelector(".govuk-exit-this-page__button");
+        if (!(n instanceof HTMLAnchorElement)) throw new ElementError({
             componentName: "Exit this page",
-            element: s,
+            element: n,
             expectedType: "HTMLAnchorElement",
             identifier: "Button (`.govuk-exit-this-page__button`)"
         });
-        this.config = mergeConfigs(ExitThisPage.defaults, t, normaliseDataset(ExitThisPage, e.dataset)), this.i18n = new I18n(this.config.i18n), this.$module = e, this.$button = s;
-        const n = document.querySelector(".govuk-js-exit-this-page-skiplink");
-        n instanceof HTMLAnchorElement && (this.$skiplinkButton = n), this.buildIndicator(), this.initUpdateSpan(), this.initButtonClickHandler(), "govukFrontendExitThisPageKeypress" in document.body.dataset || (document.addEventListener("keyup", this.handleKeypress.bind(this), !0), document.body.dataset.govukFrontendExitThisPageKeypress = "true"), window.addEventListener("pageshow", this.resetPage.bind(this))
+        this.config = mergeConfigs(ExitThisPage.defaults, t, normaliseDataset(ExitThisPage, e.dataset)), this.i18n = new I18n(this.config.i18n), this.$module = e, this.$button = n;
+        const s = document.querySelector(".govuk-js-exit-this-page-skiplink");
+        s instanceof HTMLAnchorElement && (this.$skiplinkButton = s), this.buildIndicator(), this.initUpdateSpan(), this.initButtonClickHandler(), "govukFrontendExitThisPageKeypress" in document.body.dataset || (document.addEventListener("keyup", this.handleKeypress.bind(this), !0), document.body.dataset.govukFrontendExitThisPageKeypress = "true"), window.addEventListener("pageshow", this.resetPage.bind(this))
     }
     initUpdateSpan() {
         this.$updateSpan = document.createElement("span"), this.$updateSpan.setAttribute("role", "status"), this.$updateSpan.className = "govuk-visually-hidden", this.$module.appendChild(this.$updateSpan)
@@ -754,18 +754,18 @@ class Header extends GOVUKFrontendComponent {
         this.$module = e;
         const t = e.querySelector(".govuk-js-header-toggle");
         if (!t) return this;
-        const s = t.getAttribute("aria-controls");
-        if (!s) throw new ElementError({
+        const n = t.getAttribute("aria-controls");
+        if (!n) throw new ElementError({
             componentName: "Header",
             identifier: 'Navigation button (`<button class="govuk-js-header-toggle">`) attribute (`aria-controls`)'
         });
-        const n = document.getElementById(s);
-        if (!n) throw new ElementError({
+        const s = document.getElementById(n);
+        if (!s) throw new ElementError({
             componentName: "Header",
-            element: n,
-            identifier: `Navigation (\`<ul id="${s}">\`)`
+            element: s,
+            identifier: `Navigation (\`<ul id="${n}">\`)`
         });
-        this.$menu = n, this.$menuButton = t, this.setupResponsiveChecks(), this.$menuButton.addEventListener("click", (() => this.handleMenuButtonClick()))
+        this.$menu = s, this.$menuButton = t, this.setupResponsiveChecks(), this.$menuButton.addEventListener("click", (() => this.handleMenuButtonClick()))
     }
     setupResponsiveChecks() {
         const e = getBreakpoint("desktop");
@@ -809,23 +809,23 @@ class PasswordInput extends GOVUKFrontendComponent {
             element: e,
             identifier: "Root element (`$module`)"
         });
-        const s = e.querySelector(".govuk-js-password-input-input");
-        if (!(s instanceof HTMLInputElement)) throw new ElementError({
+        const n = e.querySelector(".govuk-js-password-input-input");
+        if (!(n instanceof HTMLInputElement)) throw new ElementError({
             componentName: "Password input",
-            element: s,
+            element: n,
             expectedType: "HTMLInputElement",
             identifier: "Form field (`.govuk-js-password-input-input`)"
         });
-        if ("password" !== s.type) throw new ElementError("Password input: Form field (`.govuk-js-password-input-input`) must be of type `password`.");
-        const n = e.querySelector(".govuk-js-password-input-toggle");
-        if (!(n instanceof HTMLButtonElement)) throw new ElementError({
+        if ("password" !== n.type) throw new ElementError("Password input: Form field (`.govuk-js-password-input-input`) must be of type `password`.");
+        const s = e.querySelector(".govuk-js-password-input-toggle");
+        if (!(s instanceof HTMLButtonElement)) throw new ElementError({
             componentName: "Password input",
-            element: n,
+            element: s,
             expectedType: "HTMLButtonElement",
             identifier: "Button (`.govuk-js-password-input-toggle`)"
         });
-        if ("button" !== n.type) throw new ElementError("Password input: Button (`.govuk-js-password-input-toggle`) must be of type `button`.");
-        this.$module = e, this.$input = s, this.$showHideButton = n, this.config = mergeConfigs(PasswordInput.defaults, t, normaliseDataset(PasswordInput, e.dataset)), this.i18n = new I18n(this.config.i18n, {
+        if ("button" !== s.type) throw new ElementError("Password input: Button (`.govuk-js-password-input-toggle`) must be of type `button`.");
+        this.$module = e, this.$input = n, this.$showHideButton = s, this.config = mergeConfigs(PasswordInput.defaults, t, normaliseDataset(PasswordInput, e.dataset)), this.i18n = new I18n(this.config.i18n, {
             locale: closestAttributeValue(e, "lang")
         }), this.$showHideButton.removeAttribute("hidden");
         const i = document.createElement("div");
@@ -846,9 +846,9 @@ class PasswordInput extends GOVUKFrontendComponent {
         if (e === this.$input.type) return;
         this.$input.setAttribute("type", e);
         const t = "password" === e,
-            s = t ? "show" : "hide",
-            n = t ? "passwordHidden" : "passwordShown";
-        this.$showHideButton.innerText = this.i18n.t(`${s}Password`), this.$showHideButton.setAttribute("aria-label", this.i18n.t(`${s}PasswordAriaLabel`)), this.$screenReaderStatusMessage.innerText = this.i18n.t(`${n}Announcement`)
+            n = t ? "show" : "hide",
+            s = t ? "passwordHidden" : "passwordShown";
+        this.$showHideButton.innerText = this.i18n.t(`${n}Password`), this.$showHideButton.setAttribute("aria-label", this.i18n.t(`${n}PasswordAriaLabel`)), this.$screenReaderStatusMessage.innerText = this.i18n.t(`${s}Announcement`)
     }
 }
 PasswordInput.moduleName = "govuk-password-input", PasswordInput.defaults = Object.freeze({
@@ -896,20 +896,20 @@ class Radios extends GOVUKFrontendComponent {
     syncConditionalRevealWithInputState(e) {
         const t = e.getAttribute("aria-controls");
         if (!t) return;
-        const s = document.getElementById(t);
-        if (null != s && s.classList.contains("govuk-radios__conditional")) {
+        const n = document.getElementById(t);
+        if (null != n && n.classList.contains("govuk-radios__conditional")) {
             const t = e.checked;
-            e.setAttribute("aria-expanded", t.toString()), s.classList.toggle("govuk-radios__conditional--hidden", !t)
+            e.setAttribute("aria-expanded", t.toString()), n.classList.toggle("govuk-radios__conditional--hidden", !t)
         }
     }
     handleClick(e) {
         const t = e.target;
         if (!(t instanceof HTMLInputElement) || "radio" !== t.type) return;
-        const s = document.querySelectorAll('input[type="radio"][aria-controls]'),
-            n = t.form,
+        const n = document.querySelectorAll('input[type="radio"][aria-controls]'),
+            s = t.form,
             i = t.name;
-        s.forEach((e => {
-            const t = e.form === n;
+        n.forEach((e => {
+            const t = e.form === s;
             e.name === i && t && this.syncConditionalRevealWithInputState(e)
         }))
     }
@@ -925,17 +925,17 @@ class SkipLink extends GOVUKFrontendComponent {
             identifier: "Root element (`$module`)"
         });
         this.$module = e;
-        const s = this.$module.hash,
-            n = null != (t = this.$module.getAttribute("href")) ? t : "";
+        const n = this.$module.hash,
+            s = null != (t = this.$module.getAttribute("href")) ? t : "";
         let i;
         try {
             i = new window.URL(this.$module.href)
         } catch (a) {
-            throw new ElementError(`Skip link: Target link (\`href="${n}"\`) is invalid`)
+            throw new ElementError(`Skip link: Target link (\`href="${s}"\`) is invalid`)
         }
         if (i.origin !== window.location.origin || i.pathname !== window.location.pathname) return;
-        const o = getFragmentFromUrl(s);
-        if (!o) throw new ElementError(`Skip link: Target link (\`href="${n}"\`) has no hash fragment`);
+        const o = getFragmentFromUrl(n);
+        if (!o) throw new ElementError(`Skip link: Target link (\`href="${s}"\`) has no hash fragment`);
         const r = document.getElementById(o);
         if (!r) throw new ElementError({
             componentName: "Skip link",
@@ -966,17 +966,17 @@ class Tabs extends GOVUKFrontendComponent {
             identifier: 'Links (`<a class="govuk-tabs__tab">`)'
         });
         this.$module = e, this.$tabs = t, this.boundTabClick = this.onTabClick.bind(this), this.boundTabKeydown = this.onTabKeydown.bind(this), this.boundOnHashChange = this.onHashChange.bind(this);
-        const s = this.$module.querySelector(".govuk-tabs__list"),
-            n = this.$module.querySelectorAll("li.govuk-tabs__list-item");
-        if (!s) throw new ElementError({
+        const n = this.$module.querySelector(".govuk-tabs__list"),
+            s = this.$module.querySelectorAll("li.govuk-tabs__list-item");
+        if (!n) throw new ElementError({
             componentName: "Tabs",
             identifier: 'List (`<ul class="govuk-tabs__list">`)'
         });
-        if (!n.length) throw new ElementError({
+        if (!s.length) throw new ElementError({
             componentName: "Tabs",
             identifier: 'List items (`<li class="govuk-tabs__list-item">`)'
         });
-        this.$tabList = s, this.$tabListItems = n, this.setupResponsiveChecks()
+        this.$tabList = n, this.$tabListItems = s, this.setupResponsiveChecks()
     }
     setupResponsiveChecks() {
         const e = getBreakpoint("tablet");
@@ -1012,8 +1012,8 @@ class Tabs extends GOVUKFrontendComponent {
             t = this.getTab(e);
         if (!t) return;
         if (this.changingHash) return void(this.changingHash = !1);
-        const s = this.getCurrentTab();
-        s && (this.hideTab(s), this.showTab(t), t.focus())
+        const n = this.getCurrentTab();
+        n && (this.hideTab(n), this.showTab(t), t.focus())
     }
     hideTab(e) {
         this.unhighlightTab(e), this.hidePanel(e)
@@ -1028,8 +1028,8 @@ class Tabs extends GOVUKFrontendComponent {
         const t = getFragmentFromUrl(e.href);
         if (!t) return;
         e.setAttribute("id", `tab_${t}`), e.setAttribute("role", "tab"), e.setAttribute("aria-controls", t), e.setAttribute("aria-selected", "false"), e.setAttribute("tabindex", "-1");
-        const s = this.getPanel(e);
-        s && (s.setAttribute("role", "tabpanel"), s.setAttribute("aria-labelledby", e.id), s.classList.add(this.jsHiddenClass))
+        const n = this.getPanel(e);
+        n && (n.setAttribute("role", "tabpanel"), n.setAttribute("aria-labelledby", e.id), n.classList.add(this.jsHiddenClass))
     }
     unsetAttributes(e) {
         e.removeAttribute("id"), e.removeAttribute("role"), e.removeAttribute("aria-controls"), e.removeAttribute("aria-selected"), e.removeAttribute("tabindex");
@@ -1038,14 +1038,14 @@ class Tabs extends GOVUKFrontendComponent {
     }
     onTabClick(e) {
         const t = this.getCurrentTab(),
-            s = e.currentTarget;
-        t && s instanceof HTMLAnchorElement && (e.preventDefault(), this.hideTab(t), this.showTab(s), this.createHistoryEntry(s))
+            n = e.currentTarget;
+        t && n instanceof HTMLAnchorElement && (e.preventDefault(), this.hideTab(t), this.showTab(n), this.createHistoryEntry(n))
     }
     createHistoryEntry(e) {
         const t = this.getPanel(e);
         if (!t) return;
-        const s = t.id;
-        t.id = "", this.changingHash = !0, window.location.hash = s, t.id = s
+        const n = t.id;
+        t.id = "", this.changingHash = !0, window.location.hash = n, t.id = n
     }
     onTabKeydown(e) {
         switch (e.key) {
@@ -1067,16 +1067,16 @@ class Tabs extends GOVUKFrontendComponent {
         if (null == e || !e.parentElement) return;
         const t = e.parentElement.nextElementSibling;
         if (!t) return;
-        const s = t.querySelector("a.govuk-tabs__tab");
-        s && (this.hideTab(e), this.showTab(s), s.focus(), this.createHistoryEntry(s))
+        const n = t.querySelector("a.govuk-tabs__tab");
+        n && (this.hideTab(e), this.showTab(n), n.focus(), this.createHistoryEntry(n))
     }
     activatePreviousTab() {
         const e = this.getCurrentTab();
         if (null == e || !e.parentElement) return;
         const t = e.parentElement.previousElementSibling;
         if (!t) return;
-        const s = t.querySelector("a.govuk-tabs__tab");
-        s && (this.hideTab(e), this.showTab(s), s.focus(), this.createHistoryEntry(s))
+        const n = t.querySelector("a.govuk-tabs__tab");
+        n && (this.hideTab(e), this.showTab(n), n.focus(), this.createHistoryEntry(n))
     }
     getPanel(e) {
         const t = getFragmentFromUrl(e.href);
@@ -1104,7 +1104,7 @@ class Tabs extends GOVUKFrontendComponent {
 function initAll(e) {
     var t;
     if (e = void 0 !== e ? e : {}, !isSupported()) return void console.log(new SupportError);
-    const s = [
+    const n = [
             [Accordion, e.accordion],
             [Button, e.button],
             [CharacterCount, e.characterCount],
@@ -1118,17 +1118,22 @@ function initAll(e) {
             [SkipLink],
             [Tabs]
         ],
-        n = null != (t = e.scope) ? t : document;
-    s.forEach((([e, t]) => {
-        n.querySelectorAll(`[data-module="${e.moduleName}"]`).forEach((s => {
-            try {
-                "defaults" in e ? new e(s, t) : new e(s)
-            } catch (n) {
-                console.log(n)
-            }
-        }))
+        s = null != (t = e.scope) ? t : document;
+    n.forEach((([e, t]) => {
+        createAll(e, t, s)
     }))
 }
+
+function createAll(e, t, n = document) {
+    const s = n.querySelectorAll(`[data-module="${e.moduleName}"]`);
+    return Array.from(s).map((n => {
+        try {
+            return "defaults" in e && void 0 !== t ? new e(n, t) : new e(n)
+        } catch (s) {
+            return console.log(s), null
+        }
+    })).filter(Boolean)
+}
 Tabs.moduleName = "govuk-tabs";
 export {
     Accordion,
@@ -1143,6 +1148,7 @@ export {
     Radios,
     SkipLink,
     Tabs,
+    createAll,
     initAll,
     version
-}; //# sourceMappingURL=govuk-frontend-5.3.1.min.js.map
\ No newline at end of file
+}; //# sourceMappingURL=govuk-frontend-5.4.0.min.js.map
\ No newline at end of file

Action run for cf861ab

Copy link

github-actions bot commented May 17, 2024

Stylesheets changes to GitHub release

diff --git a/dist/govuk-frontend-5.3.1.min.css b/dist/govuk-frontend-5.4.0.min.css
index e58c0850b..0ef389ae2 100644
--- a/dist/govuk-frontend-5.3.1.min.css
+++ b/dist/govuk-frontend-5.4.0.min.css
@@ -1,7 +1,7 @@
 @charset "UTF-8";
 
 :root {
-    --govuk-frontend-version: "5.3.1";
+    --govuk-frontend-version: "5.4.0";
     --govuk-frontend-breakpoint-mobile: 20rem;
     --govuk-frontend-breakpoint-tablet: 40.0625rem;
     --govuk-frontend-breakpoint-desktop: 48.0625rem
@@ -3171,18 +3171,21 @@ screen and (forced-colors:active) {
 }
 
 .govuk-error-summary__body p {
-    margin-top: 0;
-    margin-bottom: 15px
+    margin-bottom: 0
+}
+
+.govuk-error-summary__body>*+* {
+    margin-top: 15px
 }
 
 @media (min-width:40.0625em) {
-    .govuk-error-summary__body p {
-        margin-bottom: 20px
+    .govuk-error-summary__body>*+* {
+        margin-top: 20px
     }
 }
 
-.govuk-error-summary__list {
-    margin-top: 0;
+.govuk-error-summary__list,
+.govuk-error-summary__list li:last-child {
     margin-bottom: 0
 }
 
@@ -7585,6 +7588,10 @@ screen and (-ms-high-contrast:active) {
     font-weight: 700 !important
 }
 
+.govuk-\!-font-tabular-numbers {
+    font-variant-numeric: tabular-nums !important
+}
+
 .govuk-\!-width-full,
 .govuk-\!-width-three-quarters {
     width: 100% !important
@@ -7636,4 +7643,4 @@ screen and (-ms-high-contrast:active) {
     }
 }
 
-/*# sourceMappingURL=govuk-frontend-5.3.1.min.css.map */
\ No newline at end of file
+/*# sourceMappingURL=govuk-frontend-5.4.0.min.css.map */
\ No newline at end of file

Action run for cf861ab

Copy link

github-actions bot commented May 17, 2024

Other changes to GitHub release

diff --git a/dist/VERSION.txt b/dist/VERSION.txt
index c7cb1311a..8a30e8f94 100644
--- a/dist/VERSION.txt
+++ b/dist/VERSION.txt
@@ -1 +1 @@
-5.3.1
+5.4.0

Action run for cf861ab

Copy link

github-actions bot commented May 17, 2024

📋 Stats

File sizes

File Size
dist/govuk-frontend-development.min.css 113.37 KiB
dist/govuk-frontend-development.min.js 42.34 KiB
packages/govuk-frontend/dist/govuk/all.bundle.js 88.16 KiB
packages/govuk-frontend/dist/govuk/all.bundle.mjs 82.83 KiB
packages/govuk-frontend/dist/govuk/all.mjs 981 B
packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs 359 B
packages/govuk-frontend/dist/govuk/govuk-frontend.min.css 113.36 KiB
packages/govuk-frontend/dist/govuk/govuk-frontend.min.js 42.33 KiB
packages/govuk-frontend/dist/govuk/i18n.mjs 5.55 KiB
packages/govuk-frontend/dist/govuk/init.mjs 4.86 KiB

Modules

File Size (bundled) Size (minified)
all.mjs 78.45 KiB 40.31 KiB
accordion.mjs 22.71 KiB 12.85 KiB
button.mjs 5.98 KiB 2.69 KiB
character-count.mjs 22.4 KiB 9.92 KiB
checkboxes.mjs 5.83 KiB 2.83 KiB
error-summary.mjs 7.89 KiB 3.46 KiB
exit-this-page.mjs 17.1 KiB 9.26 KiB
header.mjs 4.46 KiB 2.6 KiB
notification-banner.mjs 6.26 KiB 2.62 KiB
password-input.mjs 15.15 KiB 7.25 KiB
radios.mjs 4.83 KiB 2.38 KiB
skip-link.mjs 4.39 KiB 2.18 KiB
tabs.mjs 10.13 KiB 6.11 KiB

View stats and visualisations on the review app


Action run for cf861ab

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-4987 May 17, 2024 10:38 Inactive
@patrickpatrickpatrick patrickpatrickpatrick merged commit adfa0ab into main May 17, 2024
50 checks passed
@patrickpatrickpatrick patrickpatrickpatrick deleted the release-5.4.0 branch May 17, 2024 10:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants