diff --git a/packages/govuk-frontend/src/govuk/components/accordion/accordion.mjs b/packages/govuk-frontend/src/govuk/components/accordion/accordion.mjs index 59ebdf1fa4..8460784d11 100644 --- a/packages/govuk-frontend/src/govuk/components/accordion/accordion.mjs +++ b/packages/govuk-frontend/src/govuk/components/accordion/accordion.mjs @@ -2,23 +2,6 @@ import { mergeConfigs, extractConfigByNamespace } from '../../common/index.mjs' import { normaliseDataset } from '../../common/normalise-dataset.mjs' import { I18n } from '../../i18n.mjs' -/** - * Accordion translation defaults - * - * @see {@link AccordionConfig.i18n} - * @constant - * @default - * @type {AccordionTranslations} - */ -const ACCORDION_TRANSLATIONS = { - hideAllSections: 'Hide all sections', - hideSection: 'Hide', - hideSectionAriaLabel: 'Hide this section', - showAllSections: 'Show all sections', - showSection: 'Show', - showSectionAriaLabel: 'Show this section' -} - /** * Accordion component * @@ -44,18 +27,12 @@ export class Accordion { /** @private */ this.$module = $module - /** @type {AccordionConfig} */ - const defaultConfig = { - i18n: ACCORDION_TRANSLATIONS, - rememberExpanded: true - } - /** * @private * @type {AccordionConfig} */ this.config = mergeConfigs( - defaultConfig, + Accordion.defaults, config || {}, normaliseDataset($module.dataset) ) @@ -564,6 +541,26 @@ export class Accordion { $punctuationEl.innerHTML = ', ' return $punctuationEl } + + /** + * Accordion default config + * + * @see {@link AccordionConfig} + * @constant + * @default + * @type {AccordionConfig} + */ + static defaults = Object.freeze({ + i18n: { + hideAllSections: 'Hide all sections', + hideSection: 'Hide', + hideSectionAriaLabel: 'Hide this section', + showAllSections: 'Show all sections', + showSection: 'Show', + showSectionAriaLabel: 'Show this section' + }, + rememberExpanded: true + }) } const helper = { @@ -589,8 +586,9 @@ const helper = { /** * Accordion config * + * @see {@link Accordion.defaults} * @typedef {object} AccordionConfig - * @property {AccordionTranslations} [i18n=ACCORDION_TRANSLATIONS] - Accordion translations + * @property {AccordionTranslations} [i18n=Accordion.defaults.i18n] - Accordion translations * @property {boolean} [rememberExpanded] - Whether the expanded and collapsed * state of each section is remembered and restored when navigating. */ @@ -598,7 +596,7 @@ const helper = { /** * Accordion translations * - * @see {@link ACCORDION_TRANSLATIONS} + * @see {@link Accordion.defaults.i18n} * @typedef {object} AccordionTranslations * * Messages used by the component for the labels of its buttons. This includes diff --git a/packages/govuk-frontend/src/govuk/components/button/button.mjs b/packages/govuk-frontend/src/govuk/components/button/button.mjs index 30e806ae20..daba236832 100644 --- a/packages/govuk-frontend/src/govuk/components/button/button.mjs +++ b/packages/govuk-frontend/src/govuk/components/button/button.mjs @@ -24,17 +24,12 @@ export class Button { /** @private */ this.debounceFormSubmitTimer = null - /** @type {ButtonConfig} */ - const defaultConfig = { - preventDoubleClick: false - } - /** * @private * @type {ButtonConfig} */ this.config = mergeConfigs( - defaultConfig, + Button.defaults, config || {}, normaliseDataset($module.dataset) ) @@ -106,6 +101,18 @@ export class Button { this.debounceFormSubmitTimer = null }, DEBOUNCE_TIMEOUT_IN_SECONDS * 1000) } + + /** + * Button default config + * + * @see {@link ButtonConfig} + * @constant + * @default + * @type {ButtonConfig} + */ + static defaults = Object.freeze({ + preventDoubleClick: false + }) } /** diff --git a/packages/govuk-frontend/src/govuk/components/character-count/character-count.mjs b/packages/govuk-frontend/src/govuk/components/character-count/character-count.mjs index e934700245..a8b01bdf03 100644 --- a/packages/govuk-frontend/src/govuk/components/character-count/character-count.mjs +++ b/packages/govuk-frontend/src/govuk/components/character-count/character-count.mjs @@ -3,40 +3,6 @@ import { extractConfigByNamespace, mergeConfigs } from '../../common/index.mjs' import { normaliseDataset } from '../../common/normalise-dataset.mjs' import { I18n } from '../../i18n.mjs' -/** - * Character count translation defaults - * - * @see {@link CharacterCountConfig.i18n} - * @constant - * @default - * @type {CharacterCountTranslations} - */ -const CHARACTER_COUNT_TRANSLATIONS = { - // Characters - charactersUnderLimit: { - one: 'You have %{count} character remaining', - other: 'You have %{count} characters remaining' - }, - charactersAtLimit: 'You have 0 characters remaining', - charactersOverLimit: { - one: 'You have %{count} character too many', - other: 'You have %{count} characters too many' - }, - // Words - wordsUnderLimit: { - one: 'You have %{count} word remaining', - other: 'You have %{count} words remaining' - }, - wordsAtLimit: 'You have 0 words remaining', - wordsOverLimit: { - one: 'You have %{count} word too many', - other: 'You have %{count} words too many' - }, - textareaDescription: { - other: '' - } -} - /** * Character count component * @@ -67,12 +33,6 @@ export class CharacterCount { return this } - /** @type {CharacterCountConfig} */ - const defaultConfig = { - threshold: 0, - i18n: CHARACTER_COUNT_TRANSLATIONS - } - // Read config set using dataset ('data-' values) const datasetConfig = normaliseDataset($module.dataset) @@ -96,7 +56,7 @@ export class CharacterCount { * @type {CharacterCountConfig} */ this.config = mergeConfigs( - defaultConfig, + CharacterCount.defaults, config || {}, configOverrides, datasetConfig @@ -423,42 +383,82 @@ export class CharacterCount { return (thresholdValue <= currentLength) } + + /** + * Character count default config + * + * @see {@link CharacterCountConfig} + * @constant + * @default + * @type {CharacterCountConfig} + */ + static defaults = Object.freeze({ + threshold: 0, + i18n: { + // Characters + charactersUnderLimit: { + one: 'You have %{count} character remaining', + other: 'You have %{count} characters remaining' + }, + charactersAtLimit: 'You have 0 characters remaining', + charactersOverLimit: { + one: 'You have %{count} character too many', + other: 'You have %{count} characters too many' + }, + // Words + wordsUnderLimit: { + one: 'You have %{count} word remaining', + other: 'You have %{count} words remaining' + }, + wordsAtLimit: 'You have 0 words remaining', + wordsOverLimit: { + one: 'You have %{count} word too many', + other: 'You have %{count} words too many' + }, + textareaDescription: { + other: '' + } + } + }) } /** * Character count config * + * @see {@link CharacterCount.defaults} * @typedef {CharacterCountConfigWithMaxLength | CharacterCountConfigWithMaxWords} CharacterCountConfig */ /** * Character count config (with maximum number of characters) * + * @see {@link CharacterCount.defaults} * @typedef {object} CharacterCountConfigWithMaxLength * @property {number} [maxlength] - The maximum number of characters. * If maxwords is provided, the maxlength option will be ignored. * @property {number} [threshold=0] - The percentage value of the limit at * which point the count message is displayed. If this attribute is set, the * count message will be hidden by default. - * @property {CharacterCountTranslations} [i18n=CHARACTER_COUNT_TRANSLATIONS] - Character count translations + * @property {CharacterCountTranslations} [i18n=CharacterCount.defaults.i18n] - Character count translations */ /** * Character count config (with maximum number of words) * + * @see {@link CharacterCount.defaults} * @typedef {object} CharacterCountConfigWithMaxWords * @property {number} [maxwords] - The maximum number of words. If maxwords is * provided, the maxlength option will be ignored. * @property {number} [threshold=0] - The percentage value of the limit at * which point the count message is displayed. If this attribute is set, the * count message will be hidden by default. - * @property {CharacterCountTranslations} [i18n=CHARACTER_COUNT_TRANSLATIONS] - Character count translations + * @property {CharacterCountTranslations} [i18n=CharacterCount.defaults.i18n] - Character count translations */ /** * Character count translations * - * @see {@link CHARACTER_COUNT_TRANSLATIONS} + * @see {@link CharacterCount.defaults.i18n} * @typedef {object} CharacterCountTranslations * * Messages shown to users as they type. It provides feedback on how many words diff --git a/packages/govuk-frontend/src/govuk/components/error-summary/error-summary.mjs b/packages/govuk-frontend/src/govuk/components/error-summary/error-summary.mjs index 37703673c7..6359ad20d6 100644 --- a/packages/govuk-frontend/src/govuk/components/error-summary/error-summary.mjs +++ b/packages/govuk-frontend/src/govuk/components/error-summary/error-summary.mjs @@ -27,17 +27,12 @@ export class ErrorSummary { /** @private */ this.$module = $module - /** @type {ErrorSummaryConfig} */ - const defaultConfig = { - disableAutoFocus: false - } - /** * @private * @type {ErrorSummaryConfig} */ this.config = mergeConfigs( - defaultConfig, + ErrorSummary.defaults, config || {}, normaliseDataset($module.dataset) ) @@ -212,6 +207,18 @@ export class ErrorSummary { return document.querySelector(`label[for='${$input.getAttribute('id')}']`) || $input.closest('label') } + + /** + * Error summary default config + * + * @see {@link ErrorSummaryConfig} + * @constant + * @default + * @type {ErrorSummaryConfig} + */ + static defaults = Object.freeze({ + disableAutoFocus: false + }) } /** diff --git a/packages/govuk-frontend/src/govuk/components/notification-banner/notification-banner.mjs b/packages/govuk-frontend/src/govuk/components/notification-banner/notification-banner.mjs index df83c9f794..81a946ea87 100644 --- a/packages/govuk-frontend/src/govuk/components/notification-banner/notification-banner.mjs +++ b/packages/govuk-frontend/src/govuk/components/notification-banner/notification-banner.mjs @@ -17,17 +17,12 @@ export class NotificationBanner { /** @private */ this.$module = $module - /** @type {NotificationBannerConfig} */ - const defaultConfig = { - disableAutoFocus: false - } - /** * @private * @type {NotificationBannerConfig} */ this.config = mergeConfigs( - defaultConfig, + NotificationBanner.defaults, config || {}, normaliseDataset($module.dataset) ) @@ -79,6 +74,18 @@ export class NotificationBanner { this.$module.focus() } + + /** + * Notification banner default config + * + * @see {@link NotificationBannerConfig} + * @constant + * @default + * @type {NotificationBannerConfig} + */ + static defaults = Object.freeze({ + disableAutoFocus: false + }) } /** diff --git a/packages/govuk-frontend/src/govuk/i18n.mjs b/packages/govuk-frontend/src/govuk/i18n.mjs index 9c6a481f0c..792ec08e17 100644 --- a/packages/govuk-frontend/src/govuk/i18n.mjs +++ b/packages/govuk-frontend/src/govuk/i18n.mjs @@ -246,124 +246,124 @@ export class I18n { } } } -} -/** - * Map of plural rules to languages where those rules apply. - * - * Note: These groups are named for the most dominant or recognisable language - * that uses each system. The groupings do not imply that the languages are - * related to one another. Many languages have evolved the same systems - * independently of one another. - * - * Code to support more languages can be found in the i18n spike: - * {@link https://github.com/alphagov/govuk-frontend/blob/spike-i18n-support/src/govuk/i18n.mjs} - * - * Languages currently supported: - * - * Arabic: Arabic (ar) - * Chinese: Burmese (my), Chinese (zh), Indonesian (id), Japanese (ja), - * Javanese (jv), Korean (ko), Malay (ms), Thai (th), Vietnamese (vi) - * French: Armenian (hy), Bangla (bn), French (fr), Gujarati (gu), Hindi (hi), - * Persian Farsi (fa), Punjabi (pa), Zulu (zu) - * German: Afrikaans (af), Albanian (sq), Azerbaijani (az), Basque (eu), - * Bulgarian (bg), Catalan (ca), Danish (da), Dutch (nl), English (en), - * Estonian (et), Finnish (fi), Georgian (ka), German (de), Greek (el), - * Hungarian (hu), Luxembourgish (lb), Norwegian (no), Somali (so), - * Swahili (sw), Swedish (sv), Tamil (ta), Telugu (te), Turkish (tr), - * Urdu (ur) - * Irish: Irish Gaelic (ga) - * Russian: Russian (ru), Ukrainian (uk) - * Scottish: Scottish Gaelic (gd) - * Spanish: European Portuguese (pt-PT), Italian (it), Spanish (es) - * Welsh: Welsh (cy) - * - * @type {{ [key: string]: string[] }} - */ -I18n.pluralRulesMap = { - arabic: ['ar'], - chinese: ['my', 'zh', 'id', 'ja', 'jv', 'ko', 'ms', 'th', 'vi'], - french: ['hy', 'bn', 'fr', 'gu', 'hi', 'fa', 'pa', 'zu'], - german: [ - 'af', 'sq', 'az', 'eu', 'bg', 'ca', 'da', 'nl', 'en', 'et', 'fi', 'ka', - 'de', 'el', 'hu', 'lb', 'no', 'so', 'sw', 'sv', 'ta', 'te', 'tr', 'ur' - ], - irish: ['ga'], - russian: ['ru', 'uk'], - scottish: ['gd'], - spanish: ['pt-PT', 'it', 'es'], - welsh: ['cy'] -} + /** + * Map of plural rules to languages where those rules apply. + * + * Note: These groups are named for the most dominant or recognisable language + * that uses each system. The groupings do not imply that the languages are + * related to one another. Many languages have evolved the same systems + * independently of one another. + * + * Code to support more languages can be found in the i18n spike: + * {@link https://github.com/alphagov/govuk-frontend/blob/spike-i18n-support/src/govuk/i18n.mjs} + * + * Languages currently supported: + * + * Arabic: Arabic (ar) + * Chinese: Burmese (my), Chinese (zh), Indonesian (id), Japanese (ja), + * Javanese (jv), Korean (ko), Malay (ms), Thai (th), Vietnamese (vi) + * French: Armenian (hy), Bangla (bn), French (fr), Gujarati (gu), Hindi (hi), + * Persian Farsi (fa), Punjabi (pa), Zulu (zu) + * German: Afrikaans (af), Albanian (sq), Azerbaijani (az), Basque (eu), + * Bulgarian (bg), Catalan (ca), Danish (da), Dutch (nl), English (en), + * Estonian (et), Finnish (fi), Georgian (ka), German (de), Greek (el), + * Hungarian (hu), Luxembourgish (lb), Norwegian (no), Somali (so), + * Swahili (sw), Swedish (sv), Tamil (ta), Telugu (te), Turkish (tr), + * Urdu (ur) + * Irish: Irish Gaelic (ga) + * Russian: Russian (ru), Ukrainian (uk) + * Scottish: Scottish Gaelic (gd) + * Spanish: European Portuguese (pt-PT), Italian (it), Spanish (es) + * Welsh: Welsh (cy) + * + * @type {{ [key: string]: string[] }} + */ + static pluralRulesMap = { + arabic: ['ar'], + chinese: ['my', 'zh', 'id', 'ja', 'jv', 'ko', 'ms', 'th', 'vi'], + french: ['hy', 'bn', 'fr', 'gu', 'hi', 'fa', 'pa', 'zu'], + german: [ + 'af', 'sq', 'az', 'eu', 'bg', 'ca', 'da', 'nl', 'en', 'et', 'fi', 'ka', + 'de', 'el', 'hu', 'lb', 'no', 'so', 'sw', 'sv', 'ta', 'te', 'tr', 'ur' + ], + irish: ['ga'], + russian: ['ru', 'uk'], + scottish: ['gd'], + spanish: ['pt-PT', 'it', 'es'], + welsh: ['cy'] + } -/** - * Different pluralisation rule sets - * - * Returns the appropriate suffix for the plural form associated with `n`. - * Possible suffixes: 'zero', 'one', 'two', 'few', 'many', 'other' (the actual - * meaning of each differs per locale). 'other' should always exist, even in - * languages without plurals, such as Chinese. - * {@link https://cldr.unicode.org/index/cldr-spec/plural-rules} - * - * The count must be a positive integer. Negative numbers and decimals aren't accounted for - * - * @type {{ [key: string]: (count: number) => PluralRule }} - */ -I18n.pluralRules = { - /* eslint-disable jsdoc/require-jsdoc */ - arabic: function (n) { - if (n === 0) { return 'zero' } - if (n === 1) { return 'one' } - if (n === 2) { return 'two' } - if (n % 100 >= 3 && n % 100 <= 10) { return 'few' } - if (n % 100 >= 11 && n % 100 <= 99) { return 'many' } - return 'other' - }, - chinese: function () { - return 'other' - }, - french: function (n) { - return n === 0 || n === 1 ? 'one' : 'other' - }, - german: function (n) { - return n === 1 ? 'one' : 'other' - }, - irish: function (n) { - if (n === 1) { return 'one' } - if (n === 2) { return 'two' } - if (n >= 3 && n <= 6) { return 'few' } - if (n >= 7 && n <= 10) { return 'many' } - return 'other' - }, - russian: function (n) { - const lastTwo = n % 100 - const last = lastTwo % 10 - if (last === 1 && lastTwo !== 11) { return 'one' } - if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) { return 'few' } - if (last === 0 || (last >= 5 && last <= 9) || (lastTwo >= 11 && lastTwo <= 14)) { return 'many' } - // Note: The 'other' suffix is only used by decimal numbers in Russian. - // We don't anticipate it being used, but it's here for consistency. - return 'other' - }, - scottish: function (n) { - if (n === 1 || n === 11) { return 'one' } - if (n === 2 || n === 12) { return 'two' } - if ((n >= 3 && n <= 10) || (n >= 13 && n <= 19)) { return 'few' } - return 'other' - }, - spanish: function (n) { - if (n === 1) { return 'one' } - if (n % 1000000 === 0 && n !== 0) { return 'many' } - return 'other' - }, - welsh: function (n) { - if (n === 0) { return 'zero' } - if (n === 1) { return 'one' } - if (n === 2) { return 'two' } - if (n === 3) { return 'few' } - if (n === 6) { return 'many' } - return 'other' + /** + * Different pluralisation rule sets + * + * Returns the appropriate suffix for the plural form associated with `n`. + * Possible suffixes: 'zero', 'one', 'two', 'few', 'many', 'other' (the actual + * meaning of each differs per locale). 'other' should always exist, even in + * languages without plurals, such as Chinese. + * {@link https://cldr.unicode.org/index/cldr-spec/plural-rules} + * + * The count must be a positive integer. Negative numbers and decimals aren't accounted for + * + * @type {{ [key: string]: (count: number) => PluralRule }} + */ + static pluralRules = { + /* eslint-disable jsdoc/require-jsdoc */ + arabic (n) { + if (n === 0) { return 'zero' } + if (n === 1) { return 'one' } + if (n === 2) { return 'two' } + if (n % 100 >= 3 && n % 100 <= 10) { return 'few' } + if (n % 100 >= 11 && n % 100 <= 99) { return 'many' } + return 'other' + }, + chinese () { + return 'other' + }, + french (n) { + return n === 0 || n === 1 ? 'one' : 'other' + }, + german (n) { + return n === 1 ? 'one' : 'other' + }, + irish (n) { + if (n === 1) { return 'one' } + if (n === 2) { return 'two' } + if (n >= 3 && n <= 6) { return 'few' } + if (n >= 7 && n <= 10) { return 'many' } + return 'other' + }, + russian (n) { + const lastTwo = n % 100 + const last = lastTwo % 10 + if (last === 1 && lastTwo !== 11) { return 'one' } + if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) { return 'few' } + if (last === 0 || (last >= 5 && last <= 9) || (lastTwo >= 11 && lastTwo <= 14)) { return 'many' } + // Note: The 'other' suffix is only used by decimal numbers in Russian. + // We don't anticipate it being used, but it's here for consistency. + return 'other' + }, + scottish (n) { + if (n === 1 || n === 11) { return 'one' } + if (n === 2 || n === 12) { return 'two' } + if ((n >= 3 && n <= 10) || (n >= 13 && n <= 19)) { return 'few' } + return 'other' + }, + spanish (n) { + if (n === 1) { return 'one' } + if (n % 1000000 === 0 && n !== 0) { return 'many' } + return 'other' + }, + welsh (n) { + if (n === 0) { return 'zero' } + if (n === 1) { return 'one' } + if (n === 2) { return 'two' } + if (n === 3) { return 'few' } + if (n === 6) { return 'many' } + return 'other' + } + /* eslint-enable jsdoc/require-jsdoc */ } - /* eslint-enable jsdoc/require-jsdoc */ } /**