-
Notifications
You must be signed in to change notification settings - Fork 330
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
Prevent multiple initialisations of a single component instance #5272
Conversation
📋 StatsFile sizes
Modules
View stats and visualisations on the review app Action run for 49f0185 |
JavaScript changes to npm packagediff --git a/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js b/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
index b9eeaf5b6..69008e86f 100644
--- a/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
+++ b/packages/govuk-frontend/dist/govuk/govuk-frontend.min.js
@@ -116,9 +116,24 @@ class ElementError extends GOVUKFrontendError {
super(t), this.name = "ElementError"
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(e, t) {
+ let n = `moduleName not defined in component (\`${t}\`)`;
+ "string" == typeof e && (n = `Root element (\`$module\`) already initialised (\`${e}\`)`), super(n), this.name = "InitError"
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
- this.checkSupport()
+ constructor(e) {
+ this.checkSupport(), this.checkInitialised(e);
+ const t = this.constructor.moduleName;
+ if ("string" != typeof t) throw new InitError(t);
+ t && (null == e || e.setAttribute(`data-${t}-init`, ""))
+ }
+ checkInitialised(e) {
+ const t = this.constructor.moduleName;
+ if (e && t && function(e, t) {
+ return e instanceof HTMLElement && e.hasAttribute(`data-${t}-init`)
+ }(e, t)) throw new InitError(t)
}
checkSupport() {
if (!isSupported()) throw new SupportError
@@ -208,7 +223,7 @@ I18n.pluralRulesMap = {
};
class Accordion extends GOVUKFrontendComponent {
constructor(e, t = {}) {
- 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.$showAllButton = null, this.$showAllIcon = null, this.$showAllText = null, !(e instanceof HTMLElement)) throw new ElementError({
+ if (super(e), 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.$showAllButton = null, this.$showAllIcon = null, this.$showAllText = null, !(e instanceof HTMLElement)) throw new ElementError({
componentName: "Accordion",
element: e,
identifier: "Root element (`$module`)"
@@ -259,9 +274,9 @@ class Accordion extends GOVUKFrontendComponent {
l.classList.add(this.sectionShowHideToggleClass), l.setAttribute("data-nosnippet", "");
const c = document.createElement("span");
c.classList.add(this.sectionShowHideToggleFocusClass), l.appendChild(c);
- const h = document.createElement("span"),
- u = document.createElement("span");
- if (u.classList.add(this.upChevronIconClass), c.appendChild(u), h.classList.add(this.sectionShowHideTextClass), c.appendChild(h), o.appendChild(r), o.appendChild(this.getButtonPunctuationEl()), s) {
+ const u = document.createElement("span"),
+ h = document.createElement("span");
+ if (h.classList.add(this.upChevronIconClass), c.appendChild(h), u.classList.add(this.sectionShowHideTextClass), c.appendChild(u), o.appendChild(r), o.appendChild(this.getButtonPunctuationEl()), s) {
const e = document.createElement("span"),
t = document.createElement("span");
t.classList.add(this.sectionSummaryFocusClass), e.appendChild(t);
@@ -303,8 +318,8 @@ class Accordion extends GOVUKFrontendComponent {
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), s.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)), this.updateShowAllButton(this.areAllSectionsOpen())
+ const u = e ? this.i18n.t("hideSectionAriaLabel") : this.i18n.t("showSectionAriaLabel");
+ a.push(u), s.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)), this.updateShowAllButton(this.areAllSectionsOpen())
}
isExpanded(e) {
return e.classList.contains(this.sectionExpandedClass)
@@ -361,7 +376,7 @@ Accordion.moduleName = "govuk-accordion", Accordion.defaults = Object.freeze({
});
class Button extends GOVUKFrontendComponent {
constructor(e, t = {}) {
- if (super(), this.$module = void 0, this.config = void 0, this.debounceFormSubmitTimer = null, !(e instanceof HTMLElement)) throw new ElementError({
+ if (super(e), this.$module = void 0, this.config = void 0, this.debounceFormSubmitTimer = null, !(e instanceof HTMLElement)) throw new ElementError({
componentName: "Button",
element: e,
identifier: "Root element (`$module`)"
@@ -395,7 +410,7 @@ Button.moduleName = "govuk-button", Button.defaults = Object.freeze({
class CharacterCount extends GOVUKFrontendComponent {
constructor(e, t = {}) {
var n, i;
- 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({
+ if (super(e), 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,
identifier: "Root element (`$module`)"
@@ -442,10 +457,10 @@ class CharacterCount extends GOVUKFrontendComponent {
`${c.textContent}`.match(/^\s*$/) && (c.textContent = this.i18n.t("textareaDescription", {
count: this.maxLength
})), this.$textarea.insertAdjacentElement("afterend", c);
- const h = document.createElement("div");
- h.className = "govuk-character-count__sr-status govuk-visually-hidden", h.setAttribute("aria-live", "polite"), this.$screenReaderCountMessage = h, c.insertAdjacentElement("afterend", h);
const u = document.createElement("div");
- u.className = c.className, u.classList.add("govuk-character-count__status"), u.setAttribute("aria-hidden", "true"), this.$visibleCountMessage = u, c.insertAdjacentElement("afterend", u), c.classList.add("govuk-visually-hidden"), this.$textarea.removeAttribute("maxlength"), this.bindChangeEvents(), window.addEventListener("pageshow", (() => this.updateCountMessage())), this.updateCountMessage()
+ u.className = "govuk-character-count__sr-status govuk-visually-hidden", u.setAttribute("aria-live", "polite"), this.$screenReaderCountMessage = u, c.insertAdjacentElement("afterend", u);
+ const h = document.createElement("div");
+ h.className = c.className, h.classList.add("govuk-character-count__status"), h.setAttribute("aria-hidden", "true"), this.$visibleCountMessage = h, c.insertAdjacentElement("afterend", h), c.classList.add("govuk-visually-hidden"), this.$textarea.removeAttribute("maxlength"), this.bindChangeEvents(), window.addEventListener("pageshow", (() => this.updateCountMessage())), this.updateCountMessage()
}
bindChangeEvents() {
this.$textarea.addEventListener("keyup", (() => this.handleKeyUp())), this.$textarea.addEventListener("focus", (() => this.handleFocus())), this.$textarea.addEventListener("blur", (() => this.handleBlur()))
@@ -549,7 +564,7 @@ CharacterCount.moduleName = "govuk-character-count", CharacterCount.defaults = O
});
class Checkboxes extends GOVUKFrontendComponent {
constructor(e) {
- if (super(), this.$module = void 0, this.$inputs = void 0, !(e instanceof HTMLElement)) throw new ElementError({
+ if (super(e), this.$module = void 0, this.$inputs = void 0, !(e instanceof HTMLElement)) throw new ElementError({
componentName: "Checkboxes",
element: e,
identifier: "Root element (`$module`)"
@@ -602,7 +617,7 @@ class Checkboxes extends GOVUKFrontendComponent {
Checkboxes.moduleName = "govuk-checkboxes";
class ErrorSummary extends GOVUKFrontendComponent {
constructor(e, t = {}) {
- if (super(), this.$module = void 0, this.config = void 0, !(e instanceof HTMLElement)) throw new ElementError({
+ if (super(e), this.$module = void 0, this.config = void 0, !(e instanceof HTMLElement)) throw new ElementError({
componentName: "Error summary",
element: e,
identifier: "Root element (`$module`)"
@@ -653,7 +668,7 @@ ErrorSummary.moduleName = "govuk-error-summary", ErrorSummary.defaults = Object.
});
class ExitThisPage extends GOVUKFrontendComponent {
constructor(e, t = {}) {
- if (super(), this.$module = void 0, this.config = void 0, this.i18n = void 0, this.$button = void 0, this.$skiplinkButton = null, this.$updateSpan = null, this.$indicatorContainer = null, this.$overlay = null, this.keypressCounter = 0, this.lastKeyWasModified = !1, this.timeoutTime = 5e3, this.keypressTimeoutId = null, this.timeoutMessageId = null, !(e instanceof HTMLElement)) throw new ElementError({
+ if (super(e), this.$module = void 0, this.config = void 0, this.i18n = void 0, this.$button = void 0, this.$skiplinkButton = null, this.$updateSpan = null, this.$indicatorContainer = null, this.$overlay = null, this.keypressCounter = 0, this.lastKeyWasModified = !1, this.timeoutTime = 5e3, this.keypressTimeoutId = null, this.timeoutMessageId = null, !(e instanceof HTMLElement)) throw new ElementError({
componentName: "Exit this page",
element: e,
identifier: "Root element (`$module`)"
@@ -730,7 +745,7 @@ ExitThisPage.moduleName = "govuk-exit-this-page", ExitThisPage.defaults = Object
});
class Header extends GOVUKFrontendComponent {
constructor(e) {
- if (super(), this.$module = void 0, this.$menuButton = void 0, this.$menu = void 0, this.menuIsOpen = !1, this.mql = null, !e) throw new ElementError({
+ if (super(e), this.$module = void 0, this.$menuButton = void 0, this.$menu = void 0, this.menuIsOpen = !1, this.mql = null, !e) throw new ElementError({
componentName: "Header",
element: e,
identifier: "Root element (`$module`)"
@@ -769,7 +784,7 @@ class Header extends GOVUKFrontendComponent {
Header.moduleName = "govuk-header";
class NotificationBanner extends GOVUKFrontendComponent {
constructor(e, t = {}) {
- if (super(), this.$module = void 0, this.config = void 0, !(e instanceof HTMLElement)) throw new ElementError({
+ if (super(e), this.$module = void 0, this.config = void 0, !(e instanceof HTMLElement)) throw new ElementError({
componentName: "Notification banner",
element: e,
identifier: "Root element (`$module`)"
@@ -853,7 +868,7 @@ PasswordInput.moduleName = "govuk-password-input", PasswordInput.defaults = Obje
});
class Radios extends GOVUKFrontendComponent {
constructor(e) {
- if (super(), this.$module = void 0, this.$inputs = void 0, !(e instanceof HTMLElement)) throw new ElementError({
+ if (super(e), this.$module = void 0, this.$inputs = void 0, !(e instanceof HTMLElement)) throw new ElementError({
componentName: "Radios",
element: e,
identifier: "Root element (`$module`)"
@@ -941,7 +956,7 @@ ServiceNavigation.moduleName = "govuk-service-navigation";
class SkipLink extends GOVUKFrontendComponent {
constructor(e) {
var t;
- if (super(), this.$module = void 0, !(e instanceof HTMLAnchorElement)) throw new ElementError({
+ if (super(e), this.$module = void 0, !(e instanceof HTMLAnchorElement)) throw new ElementError({
componentName: "Skip link",
element: e,
expectedType: "HTMLAnchorElement",
@@ -978,7 +993,7 @@ class SkipLink extends GOVUKFrontendComponent {
SkipLink.moduleName = "govuk-skip-link";
class Tabs extends GOVUKFrontendComponent {
constructor(e) {
- if (super(), this.$module = void 0, this.$tabs = void 0, this.$tabList = void 0, this.$tabListItems = void 0, this.jsHiddenClass = "govuk-tabs__panel--hidden", this.changingHash = !1, this.boundTabClick = void 0, this.boundTabKeydown = void 0, this.boundOnHashChange = void 0, this.mql = null, !e) throw new ElementError({
+ if (super(e), this.$module = void 0, this.$tabs = void 0, this.$tabList = void 0, this.$tabListItems = void 0, this.jsHiddenClass = "govuk-tabs__panel--hidden", this.changingHash = !1, this.boundTabClick = void 0, this.boundTabKeydown = void 0, this.boundOnHashChange = void 0, this.mql = null, !e) throw new ElementError({
componentName: "Tabs",
element: e,
identifier: "Root element (`$module`)"
Action run for 49f0185 |
Other changes to npm packagediff --git a/packages/govuk-frontend/dist/govuk/all.bundle.js b/packages/govuk-frontend/dist/govuk/all.bundle.js
index f410a7790..f4c1a5628 100644
--- a/packages/govuk-frontend/dist/govuk/all.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/all.bundle.js
@@ -114,6 +114,9 @@
(_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
$element.focus();
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -234,10 +237,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -246,6 +272,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
class I18n {
constructor(translations = {}, config = {}) {
var _config$locale;
@@ -459,7 +494,7 @@
* @param {AccordionConfig} [config] - Accordion config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.i18n = void 0;
@@ -802,7 +837,7 @@
* @param {ButtonConfig} [config] - Button config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.debounceFormSubmitTimer = null;
@@ -889,7 +924,7 @@
*/
constructor($module, config = {}) {
var _ref, _this$config$maxwords;
- super();
+ super($module);
this.$module = void 0;
this.$textarea = void 0;
this.$visibleCountMessage = void 0;
@@ -1186,7 +1221,7 @@
* @param {Element | null} $module - HTML element to use for checkboxes
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$inputs = void 0;
if (!($module instanceof HTMLElement)) {
@@ -1294,7 +1329,7 @@
* @param {ErrorSummaryConfig} [config] - Error summary config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
if (!($module instanceof HTMLElement)) {
@@ -1397,7 +1432,7 @@
* @param {ExitThisPageConfig} [config] - Exit This Page config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.i18n = void 0;
@@ -1626,7 +1661,7 @@
* @param {Element | null} $module - HTML element to use for header
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$menuButton = void 0;
this.$menu = void 0;
@@ -1715,7 +1750,7 @@
* @param {NotificationBannerConfig} [config] - Notification banner config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
if (!($module instanceof HTMLElement)) {
@@ -1933,7 +1968,7 @@
* @param {Element | null} $module - HTML element to use for radios
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$inputs = void 0;
if (!($module instanceof HTMLElement)) {
@@ -2106,7 +2141,7 @@
*/
constructor($module) {
var _this$$module$getAttr;
- super();
+ super($module);
this.$module = void 0;
if (!($module instanceof HTMLAnchorElement)) {
throw new ElementError({
@@ -2162,7 +2197,7 @@
* @param {Element | null} $module - HTML element to use for tabs
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$tabs = void 0;
this.$tabList = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/all.bundle.mjs b/packages/govuk-frontend/dist/govuk/all.bundle.mjs
index efa49cc02..8e29d1ad1 100644
--- a/packages/govuk-frontend/dist/govuk/all.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/all.bundle.mjs
@@ -108,6 +108,9 @@ function setFocus($element, options = {}) {
(_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
$element.focus();
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -228,10 +231,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -240,6 +266,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
class I18n {
constructor(translations = {}, config = {}) {
var _config$locale;
@@ -453,7 +488,7 @@ class Accordion extends GOVUKFrontendComponent {
* @param {AccordionConfig} [config] - Accordion config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.i18n = void 0;
@@ -796,7 +831,7 @@ class Button extends GOVUKFrontendComponent {
* @param {ButtonConfig} [config] - Button config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.debounceFormSubmitTimer = null;
@@ -883,7 +918,7 @@ class CharacterCount extends GOVUKFrontendComponent {
*/
constructor($module, config = {}) {
var _ref, _this$config$maxwords;
- super();
+ super($module);
this.$module = void 0;
this.$textarea = void 0;
this.$visibleCountMessage = void 0;
@@ -1180,7 +1215,7 @@ class Checkboxes extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for checkboxes
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$inputs = void 0;
if (!($module instanceof HTMLElement)) {
@@ -1288,7 +1323,7 @@ class ErrorSummary extends GOVUKFrontendComponent {
* @param {ErrorSummaryConfig} [config] - Error summary config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
if (!($module instanceof HTMLElement)) {
@@ -1391,7 +1426,7 @@ class ExitThisPage extends GOVUKFrontendComponent {
* @param {ExitThisPageConfig} [config] - Exit This Page config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.i18n = void 0;
@@ -1620,7 +1655,7 @@ class Header extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for header
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$menuButton = void 0;
this.$menu = void 0;
@@ -1709,7 +1744,7 @@ class NotificationBanner extends GOVUKFrontendComponent {
* @param {NotificationBannerConfig} [config] - Notification banner config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
if (!($module instanceof HTMLElement)) {
@@ -1927,7 +1962,7 @@ class Radios extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for radios
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$inputs = void 0;
if (!($module instanceof HTMLElement)) {
@@ -2100,7 +2135,7 @@ class SkipLink extends GOVUKFrontendComponent {
*/
constructor($module) {
var _this$$module$getAttr;
- super();
+ super($module);
this.$module = void 0;
if (!($module instanceof HTMLAnchorElement)) {
throw new ElementError({
@@ -2156,7 +2191,7 @@ class Tabs extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for tabs
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$tabs = void 0;
this.$tabList = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/common/index.mjs b/packages/govuk-frontend/dist/govuk/common/index.mjs
index f1259e9dd..e3aafbbb9 100644
--- a/packages/govuk-frontend/dist/govuk/common/index.mjs
+++ b/packages/govuk-frontend/dist/govuk/common/index.mjs
@@ -79,6 +79,9 @@ function setFocus($element, options = {}) {
(_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
$element.focus();
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -145,5 +148,5 @@ function isObject(option) {
* @property {string} errorMessage - Error message when required config fields not provided
*/
-export { extractConfigByNamespace, getBreakpoint, getFragmentFromUrl, isSupported, mergeConfigs, setFocus, validateConfig };
+export { extractConfigByNamespace, getBreakpoint, getFragmentFromUrl, isInitialised, isSupported, mergeConfigs, setFocus, validateConfig };
//# sourceMappingURL=index.mjs.map
diff --git a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js
index d9a9f6fb4..1ea530bf9 100644
--- a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js
@@ -74,6 +74,9 @@
}
return newObject[namespace];
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -168,10 +171,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -180,6 +206,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
class I18n {
constructor(translations = {}, config = {}) {
var _config$locale;
@@ -393,7 +428,7 @@
* @param {AccordionConfig} [config] - Accordion config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs
index 426470026..941d494c1 100644
--- a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs
@@ -68,6 +68,9 @@ function extractConfigByNamespace(Component, dataset, namespace) {
}
return newObject[namespace];
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -162,10 +165,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -174,6 +200,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
class I18n {
constructor(translations = {}, config = {}) {
var _config$locale;
@@ -387,7 +422,7 @@ class Accordion extends GOVUKFrontendComponent {
* @param {AccordionConfig} [config] - Accordion config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.mjs b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.mjs
index 990abb949..31a0ee243 100644
--- a/packages/govuk-frontend/dist/govuk/components/accordion/accordion.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/accordion/accordion.mjs
@@ -24,7 +24,7 @@ class Accordion extends GOVUKFrontendComponent {
* @param {AccordionConfig} [config] - Accordion config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/button/button.bundle.js b/packages/govuk-frontend/dist/govuk/components/button/button.bundle.js
index 4fa64a9c3..7c75d4d98 100644
--- a/packages/govuk-frontend/dist/govuk/components/button/button.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/button/button.bundle.js
@@ -74,6 +74,9 @@
}
return newObject[namespace];
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -168,10 +171,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -180,6 +206,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
const DEBOUNCE_TIMEOUT_IN_SECONDS = 1;
/**
@@ -193,7 +228,7 @@
* @param {ButtonConfig} [config] - Button config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.debounceFormSubmitTimer = null;
diff --git a/packages/govuk-frontend/dist/govuk/components/button/button.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/button/button.bundle.mjs
index 767533419..fc488920a 100644
--- a/packages/govuk-frontend/dist/govuk/components/button/button.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/button/button.bundle.mjs
@@ -68,6 +68,9 @@ function extractConfigByNamespace(Component, dataset, namespace) {
}
return newObject[namespace];
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -162,10 +165,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -174,6 +200,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
const DEBOUNCE_TIMEOUT_IN_SECONDS = 1;
/**
@@ -187,7 +222,7 @@ class Button extends GOVUKFrontendComponent {
* @param {ButtonConfig} [config] - Button config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.debounceFormSubmitTimer = null;
diff --git a/packages/govuk-frontend/dist/govuk/components/button/button.mjs b/packages/govuk-frontend/dist/govuk/components/button/button.mjs
index db2683005..270e90a7a 100644
--- a/packages/govuk-frontend/dist/govuk/components/button/button.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/button/button.mjs
@@ -16,7 +16,7 @@ class Button extends GOVUKFrontendComponent {
* @param {ButtonConfig} [config] - Button config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.debounceFormSubmitTimer = null;
diff --git a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js
index 3a0f99791..92e9f8559 100644
--- a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js
@@ -79,6 +79,9 @@
}
return newObject[namespace];
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -199,10 +202,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -211,6 +237,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
class I18n {
constructor(translations = {}, config = {}) {
var _config$locale;
@@ -423,7 +458,7 @@
*/
constructor($module, config = {}) {
var _ref, _this$config$maxwords;
- super();
+ super($module);
this.$module = void 0;
this.$textarea = void 0;
this.$visibleCountMessage = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs
index 411789bab..bf3f2865c 100644
--- a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs
@@ -73,6 +73,9 @@ function extractConfigByNamespace(Component, dataset, namespace) {
}
return newObject[namespace];
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -193,10 +196,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -205,6 +231,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
class I18n {
constructor(translations = {}, config = {}) {
var _config$locale;
@@ -417,7 +452,7 @@ class CharacterCount extends GOVUKFrontendComponent {
*/
constructor($module, config = {}) {
var _ref, _this$config$maxwords;
- super();
+ super($module);
this.$module = void 0;
this.$textarea = void 0;
this.$visibleCountMessage = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.mjs b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.mjs
index 955e4ef16..7ab241064 100644
--- a/packages/govuk-frontend/dist/govuk/components/character-count/character-count.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/character-count/character-count.mjs
@@ -24,7 +24,7 @@ class CharacterCount extends GOVUKFrontendComponent {
*/
constructor($module, config = {}) {
var _ref, _this$config$maxwords;
- super();
+ super($module);
this.$module = void 0;
this.$textarea = void 0;
this.$visibleCountMessage = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js
index 9750c9804..459b25eda 100644
--- a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js
@@ -39,6 +39,20 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
+
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -80,8 +94,21 @@
*/
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -90,6 +117,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Checkboxes component
*
@@ -111,7 +147,7 @@
* @param {Element | null} $module - HTML element to use for checkboxes
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$inputs = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs
index e6bc6213e..49bdeba72 100644
--- a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs
@@ -33,6 +33,20 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
+
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -74,8 +88,21 @@ function isSupported($scope = document.body) {
*/
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -84,6 +111,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Checkboxes component
*
@@ -105,7 +141,7 @@ class Checkboxes extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for checkboxes
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$inputs = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs
index f9d7d8fbf..5f34b5a12 100644
--- a/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs
@@ -22,7 +22,7 @@ class Checkboxes extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for checkboxes
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$inputs = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js
index bf90c6db5..11dde3fc3 100644
--- a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js
@@ -104,6 +104,9 @@
(_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
$element.focus();
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -198,10 +201,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -210,6 +236,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Error summary component
*
@@ -224,7 +259,7 @@
* @param {ErrorSummaryConfig} [config] - Error summary config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs
index cb21f83ca..32d877a4b 100644
--- a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs
@@ -98,6 +98,9 @@ function setFocus($element, options = {}) {
(_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
$element.focus();
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -192,10 +195,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -204,6 +230,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Error summary component
*
@@ -218,7 +253,7 @@ class ErrorSummary extends GOVUKFrontendComponent {
* @param {ErrorSummaryConfig} [config] - Error summary config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs
index 1fd0f166e..7be510b70 100644
--- a/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs
@@ -17,7 +17,7 @@ class ErrorSummary extends GOVUKFrontendComponent {
* @param {ErrorSummaryConfig} [config] - Error summary config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js
index 215fa91f6..db5ac14ff 100644
--- a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js
@@ -74,6 +74,9 @@
}
return newObject[namespace];
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -168,10 +171,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -180,6 +206,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
class I18n {
constructor(translations = {}, config = {}) {
var _config$locale;
@@ -384,7 +419,7 @@
* @param {ExitThisPageConfig} [config] - Exit This Page config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs
index 8b9ae0812..bca3e20dd 100644
--- a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs
@@ -68,6 +68,9 @@ function extractConfigByNamespace(Component, dataset, namespace) {
}
return newObject[namespace];
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -162,10 +165,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -174,6 +200,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
class I18n {
constructor(translations = {}, config = {}) {
var _config$locale;
@@ -378,7 +413,7 @@ class ExitThisPage extends GOVUKFrontendComponent {
* @param {ExitThisPageConfig} [config] - Exit This Page config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs
index b4cd38985..7ad1c9360 100644
--- a/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs
@@ -15,7 +15,7 @@ class ExitThisPage extends GOVUKFrontendComponent {
* @param {ExitThisPageConfig} [config] - Exit This Page config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
this.i18n = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/header/header.bundle.js b/packages/govuk-frontend/dist/govuk/components/header/header.bundle.js
index d1d56b9bc..2977098ff 100644
--- a/packages/govuk-frontend/dist/govuk/components/header/header.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/header/header.bundle.js
@@ -12,6 +12,9 @@
value: value || undefined
};
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -87,10 +90,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -99,6 +125,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Header component
*
@@ -112,7 +147,7 @@
* @param {Element | null} $module - HTML element to use for header
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$menuButton = void 0;
this.$menu = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/header/header.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/header/header.bundle.mjs
index f850fc1f5..81aa86e4b 100644
--- a/packages/govuk-frontend/dist/govuk/components/header/header.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/header/header.bundle.mjs
@@ -6,6 +6,9 @@ function getBreakpoint(name) {
value: value || undefined
};
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -81,10 +84,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -93,6 +119,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Header component
*
@@ -106,7 +141,7 @@ class Header extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for header
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$menuButton = void 0;
this.$menu = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/header/header.mjs b/packages/govuk-frontend/dist/govuk/components/header/header.mjs
index cd6832271..a464c6b1f 100644
--- a/packages/govuk-frontend/dist/govuk/components/header/header.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/header/header.mjs
@@ -15,7 +15,7 @@ class Header extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for header
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$menuButton = void 0;
this.$menu = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js
index e100700c3..9fe1ed201 100644
--- a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js
@@ -98,6 +98,9 @@
(_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
$element.focus();
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -192,10 +195,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -204,6 +230,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Notification Banner component
*
@@ -215,7 +250,7 @@
* @param {NotificationBannerConfig} [config] - Notification banner config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs
index 2016e5f6f..816f0c522 100644
--- a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs
@@ -92,6 +92,9 @@ function setFocus($element, options = {}) {
(_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
$element.focus();
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -186,10 +189,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -198,6 +224,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Notification Banner component
*
@@ -209,7 +244,7 @@ class NotificationBanner extends GOVUKFrontendComponent {
* @param {NotificationBannerConfig} [config] - Notification banner config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs
index 1ef1621bc..77e2b61d6 100644
--- a/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs
@@ -14,7 +14,7 @@ class NotificationBanner extends GOVUKFrontendComponent {
* @param {NotificationBannerConfig} [config] - Notification banner config
*/
constructor($module, config = {}) {
- super();
+ super($module);
this.$module = void 0;
this.config = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js b/packages/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js
index a72f6fe34..ad6b0bcae 100644
--- a/packages/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js
@@ -79,6 +79,9 @@
}
return newObject[namespace];
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -173,10 +176,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -185,6 +211,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
class I18n {
constructor(translations = {}, config = {}) {
var _config$locale;
diff --git a/packages/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs
index a05806da4..75dd1d46e 100644
--- a/packages/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs
@@ -73,6 +73,9 @@ function extractConfigByNamespace(Component, dataset, namespace) {
}
return newObject[namespace];
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -167,10 +170,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -179,6 +205,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
class I18n {
constructor(translations = {}, config = {}) {
var _config$locale;
diff --git a/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.js b/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.js
index 493e0e50c..eb9602c40 100644
--- a/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.js
@@ -39,6 +39,20 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
+
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -80,8 +94,21 @@
*/
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -90,6 +117,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Radios component
*
@@ -111,7 +147,7 @@
* @param {Element | null} $module - HTML element to use for radios
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$inputs = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs
index f2f80a00f..61a06be92 100644
--- a/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs
@@ -33,6 +33,20 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
+
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -74,8 +88,21 @@ function isSupported($scope = document.body) {
*/
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -84,6 +111,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Radios component
*
@@ -105,7 +141,7 @@ class Radios extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for radios
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$inputs = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/radios/radios.mjs b/packages/govuk-frontend/dist/govuk/components/radios/radios.mjs
index ed29c7b0a..f74cefb64 100644
--- a/packages/govuk-frontend/dist/govuk/components/radios/radios.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/radios/radios.mjs
@@ -22,7 +22,7 @@ class Radios extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for radios
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$inputs = void 0;
if (!($module instanceof HTMLElement)) {
diff --git a/packages/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js b/packages/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js
index 0124f7b37..18831fdb6 100644
--- a/packages/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js
@@ -12,6 +12,9 @@
value: value || undefined
};
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -87,10 +90,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -99,6 +125,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Service Navigation component
*
diff --git a/packages/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs
index 9a0300ddb..99a6ff9f7 100644
--- a/packages/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs
@@ -6,6 +6,9 @@ function getBreakpoint(name) {
value: value || undefined
};
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -81,10 +84,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -93,6 +119,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Service Navigation component
*
diff --git a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js
index 5e5be27e9..9103ddf5f 100644
--- a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js
@@ -34,6 +34,9 @@
(_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
$element.focus();
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -109,10 +112,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -121,6 +147,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Skip link component
*
@@ -135,7 +170,7 @@
*/
constructor($module) {
var _this$$module$getAttr;
- super();
+ super($module);
this.$module = void 0;
if (!($module instanceof HTMLAnchorElement)) {
throw new ElementError({
diff --git a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs
index 13441668c..49a20e142 100644
--- a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs
@@ -28,6 +28,9 @@ function setFocus($element, options = {}) {
(_options$onBeforeFocu = options.onBeforeFocus) == null || _options$onBeforeFocu.call($element);
$element.focus();
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -103,10 +106,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -115,6 +141,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Skip link component
*
@@ -129,7 +164,7 @@ class SkipLink extends GOVUKFrontendComponent {
*/
constructor($module) {
var _this$$module$getAttr;
- super();
+ super($module);
this.$module = void 0;
if (!($module instanceof HTMLAnchorElement)) {
throw new ElementError({
diff --git a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs
index 03fb0498c..90e6fc436 100644
--- a/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs
@@ -16,7 +16,7 @@ class SkipLink extends GOVUKFrontendComponent {
*/
constructor($module) {
var _this$$module$getAttr;
- super();
+ super($module);
this.$module = void 0;
if (!($module instanceof HTMLAnchorElement)) {
throw new ElementError({
diff --git a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js
index cb5d7de9c..64f4c4c80 100644
--- a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js
+++ b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js
@@ -18,6 +18,9 @@
value: value || undefined
};
}
+ function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+ }
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -93,10 +96,33 @@
this.name = 'ElementError';
}
}
+ class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+ }
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -105,6 +131,15 @@
}
}
+ /**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+ /**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Tabs component
*
@@ -115,7 +150,7 @@
* @param {Element | null} $module - HTML element to use for tabs
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$tabs = void 0;
this.$tabList = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs
index 29d45d0e2..d1da839a3 100644
--- a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs
@@ -12,6 +12,9 @@ function getBreakpoint(name) {
value: value || undefined
};
}
+function isInitialised($module, moduleName) {
+ return $module instanceof HTMLElement && $module.hasAttribute(`data-${moduleName}-init`);
+}
/**
* Checks if GOV.UK Frontend is supported on this page
@@ -87,10 +90,33 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -99,6 +125,15 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
/**
* Tabs component
*
@@ -109,7 +144,7 @@ class Tabs extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for tabs
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$tabs = void 0;
this.$tabList = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.mjs b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.mjs
index 82296adc4..50a2cad7a 100644
--- a/packages/govuk-frontend/dist/govuk/components/tabs/tabs.mjs
+++ b/packages/govuk-frontend/dist/govuk/components/tabs/tabs.mjs
@@ -12,7 +12,7 @@ class Tabs extends GOVUKFrontendComponent {
* @param {Element | null} $module - HTML element to use for tabs
*/
constructor($module) {
- super();
+ super($module);
this.$module = void 0;
this.$tabs = void 0;
this.$tabList = void 0;
diff --git a/packages/govuk-frontend/dist/govuk/errors/index.mjs b/packages/govuk-frontend/dist/govuk/errors/index.mjs
index 9a0f05478..5fdb0858c 100644
--- a/packages/govuk-frontend/dist/govuk/errors/index.mjs
+++ b/packages/govuk-frontend/dist/govuk/errors/index.mjs
@@ -39,6 +39,16 @@ class ElementError extends GOVUKFrontendError {
this.name = 'ElementError';
}
}
+class InitError extends GOVUKFrontendError {
+ constructor(moduleName, className) {
+ let errorText = `moduleName not defined in component (\`${className}\`)`;
+ if (typeof moduleName === 'string') {
+ errorText = `Root element (\`$module\`) already initialised (\`${moduleName}\`)`;
+ }
+ super(errorText);
+ this.name = 'InitError';
+ }
+}
-export { ConfigError, ElementError, GOVUKFrontendError, SupportError };
+export { ConfigError, ElementError, GOVUKFrontendError, InitError, SupportError };
//# sourceMappingURL=index.mjs.map
diff --git a/packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs b/packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs
index 79a580f74..dac155c9c 100644
--- a/packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs
+++ b/packages/govuk-frontend/dist/govuk/govuk-frontend-component.mjs
@@ -1,9 +1,22 @@
-import { isSupported } from './common/index.mjs';
-import { SupportError } from './errors/index.mjs';
+import { isInitialised, isSupported } from './common/index.mjs';
+import { InitError, SupportError } from './errors/index.mjs';
class GOVUKFrontendComponent {
- constructor() {
+ constructor($module) {
this.checkSupport();
+ this.checkInitialised($module);
+ const moduleName = this.constructor.moduleName;
+ if (typeof moduleName === 'string') {
+ moduleName && ($module == null ? void 0 : $module.setAttribute(`data-${moduleName}-init`, ''));
+ } else {
+ throw new InitError(moduleName);
+ }
+ }
+ checkInitialised($module) {
+ const moduleName = this.constructor.moduleName;
+ if ($module && moduleName && isInitialised($module, moduleName)) {
+ throw new InitError(moduleName);
+ }
}
checkSupport() {
if (!isSupported()) {
@@ -12,5 +25,14 @@ class GOVUKFrontendComponent {
}
}
+/**
+ * @typedef ChildClass
+ * @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
+ */
+
+/**
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
+ */
+
export { GOVUKFrontendComponent };
//# sourceMappingURL=govuk-frontend-component.mjs.map
Action run for 49f0185 |
export function isInitialised($module, moduleName) { | ||
return ( | ||
$module instanceof HTMLElement && | ||
`${kebabCaseToCamelCase(moduleName)}Init` in $module.dataset |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`${kebabCaseToCamelCase(moduleName)}Init` in $module.dataset | |
$module.hasAttribute(`data-${moduleName}-init`) |
We can avoid the kebabCaseToCamelCase
if we look for the attribute. Also wondering if that function wouldn't be better exported by same module as the base component class one, to regroup the concept for computing the name of that attribute in a single file.
*/ | ||
constructor() { | ||
constructor($module, moduleName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion The moduleName
set on a child class can be accessed via this.constructor.moduleName
. This would avoid classes inheriting to have to pass the moduleName
to the constructor.
TypeScript may have complaints about this, as there's nothing in the types saying that the child class would have that static property. The base class could check for something like if (typeof this.constructor.moduleName !== 'string')
which would both set the type and let users know they're inheriting the class properly 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we added that check in the constructor, we'd then be able to make the InitError
more informative:
- say that the component is already initialised if
moduleName
is a string - say that the
moduleName
is not the right type if it's anything else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still wondering if we shouldn't have moduleName
be a mandatory thing to specify. Since it is used in other places also to create and init components.
849146f
to
1c9f255
Compare
1c9f255
to
724732b
Compare
724732b
to
700267d
Compare
700267d
to
21a6103
Compare
21a6103
to
1f8cfd5
Compare
if (typeof moduleName === 'string') { | ||
moduleName && $module?.setAttribute(`data-${moduleName}-init`, 'true') | ||
} else { | ||
throw new InitError(moduleName, this.constructor.name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue this.constructor.name
is at risk of getting mangled by Terser and other code minifiers (making class Accordion
become class N
) if the name
is not defined as a static property in the class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, would this just be a matter for adding it for our components and then adding to documentation a recommendation to specify the class name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@patrickpatrickpatrick I think we can do without putting the constructor's name
inside the message. The information is already available in the stacktrace, which will have an entry for the component's constructor and let people find which component has an issue.
/** | ||
* @type {string|undefined} | ||
*/ | ||
static moduleName |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion Rather than adding an empty static property in JavaScript to solve a TypeScript issue, what if we tried in types by defining a type for the shape we expect for the constructor of a child class:
/**
* @typedef {typeof GOVUKFrontendComponent} ChildClassConstructor
* @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
*/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if there's not some overlap with the CompatibleClass
type as well, but maybe not as createAll
does not necessarily need a child of GOVUKFrontendComponent
🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think I got this working without static moduleName
by creating another type and then combining that type and the type of GOVUKFrontendComponent
1f8cfd5
to
347d37d
Compare
JavaScript changes to GitHub releaseNo diff changes found. Action run for 347d37d |
Stylesheets changes to GitHub releaseNo diff changes found. Action run for 347d37d |
347d37d
to
52b4cd9
Compare
52b4cd9
to
98ed672
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple of last thoughts, let me know if it sounds OK.
export function isInitialised($module, moduleName) { | ||
return ( | ||
$module instanceof HTMLElement && | ||
!!$module.getAttribute(`data-${moduleName}-init`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion Rather than the double negation, we can use $module.hasAttribute
as we don't particularly care about the value of the attribute, just its presence.
if (typeof moduleName === 'string') { | ||
moduleName && $module?.setAttribute(`data-${moduleName}-init`, 'true') | ||
} else { | ||
throw new InitError(moduleName, this.constructor.name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@patrickpatrickpatrick I think we can do without putting the constructor's name
inside the message. The information is already available in the stacktrace, which will have an entry for the component's constructor and let people find which component has an issue.
.moduleName | ||
|
||
if (typeof moduleName === 'string') { | ||
moduleName && $module?.setAttribute(`data-${moduleName}-init`, 'true') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion We can keep the HTML slightly lighter by setting that attribute to ''
rather than true
(and checking with hasAttribute
which saves some !!
casting, as described in the previous comment.).
moduleName && $module?.setAttribute(`data-${moduleName}-init`, 'true') | |
moduleName && $module?.setAttribute(`data-${moduleName}-init`, '') |
a35cab2
to
11d1366
Compare
11d1366
to
49f0185
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to go! Thanks for these last amends 😊
What
New method for checking if component has already been initialised based on the value of a data attribute on the
module
of the component instance.Based on the previous work of @colinrotherham (#4561) and https://github.com/alphagov/govuk_publishing_components/ approach to initialising multiple different modules on a single DOM element.
Why
Prevent multiple initialisations of a single component on single element.
Closes: #1127