govuk_tech_docs 6.5.2.1 → 6.6.0.rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/publish-gem.yaml +1 -1
- data/lib/assets/stylesheets/_govuk_tech_docs.scss +39 -1
- data/lib/govuk_tech_docs/version.rb +1 -1
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +202 -137
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +202 -137
- data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +5 -1
- data/node_modules/govuk-frontend/dist/govuk/common/create-element.mjs +13 -0
- data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/component.mjs +2 -1
- data/node_modules/govuk-frontend/dist/govuk/components/_index.import.scss +2 -0
- data/node_modules/govuk-frontend/dist/govuk/components/_index.scss +2 -0
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +87 -62
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +87 -62
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +60 -56
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +90 -32
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +90 -32
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +64 -27
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/cookie-banner/_mixin.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +43 -18
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +43 -18
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs +16 -12
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/_feedback.import.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/_index.import.scss +8 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/_index.scss +5 -0
- data/node_modules/govuk-frontend/dist/govuk/components/feedback/_mixin.scss +48 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js +54 -30
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs +54 -30
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs +27 -24
- data/node_modules/govuk-frontend/dist/govuk/components/footer/_mixin.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_index.import.scss +8 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_index.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_language-navigation.import.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_mixin.scss +68 -0
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +17 -6
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +32 -9
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +32 -9
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs +5 -3
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/_mixin.scss +48 -3
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +14 -6
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +14 -6
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs +2 -1
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +12 -5
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +12 -5
- data/node_modules/govuk-frontend/dist/govuk/custom-properties/_frontend-version.mixin.scss +1 -1
- data/node_modules/govuk-frontend/dist/govuk/custom-properties/_functional-colours.mixin.scss +1 -0
- data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs +8 -5
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
- data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss +1 -1
- data/node_modules/govuk-frontend/dist/govuk/init.mjs +8 -8
- data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss +16 -2
- data/package-lock.json +4 -4
- data/package.json +1 -1
- metadata +10 -1
data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs
CHANGED
|
@@ -28,6 +28,9 @@ function isArray(option) {
|
|
|
28
28
|
function isObject(option) {
|
|
29
29
|
return !!option && typeof option === 'object' && !isArray(option);
|
|
30
30
|
}
|
|
31
|
+
function isScope($scope) {
|
|
32
|
+
return !!$scope && ($scope instanceof Element || $scope instanceof Document);
|
|
33
|
+
}
|
|
31
34
|
function formatErrorMessage(Component, message) {
|
|
32
35
|
return `${Component.moduleName}: ${message}`;
|
|
33
36
|
}
|
|
@@ -46,11 +49,14 @@ class SupportError extends GOVUKFrontendError {
|
|
|
46
49
|
/**
|
|
47
50
|
* Checks if GOV.UK Frontend is supported on this page
|
|
48
51
|
*
|
|
49
|
-
* @param {
|
|
52
|
+
* @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
|
|
50
53
|
*/
|
|
51
|
-
constructor(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
constructor(scopeOrMessage = document.body) {
|
|
55
|
+
let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
|
|
56
|
+
if (!isScope(scopeOrMessage)) {
|
|
57
|
+
supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
|
|
58
|
+
}
|
|
59
|
+
super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
|
|
54
60
|
this.name = 'SupportError';
|
|
55
61
|
}
|
|
56
62
|
}
|
|
@@ -91,6 +97,7 @@ class InitError extends GOVUKFrontendError {
|
|
|
91
97
|
* @import { ComponentWithModuleName } from '../common/index.mjs'
|
|
92
98
|
*/
|
|
93
99
|
|
|
100
|
+
const _self = typeof globalThis !== 'undefined' ? globalThis : self;
|
|
94
101
|
class Component {
|
|
95
102
|
/**
|
|
96
103
|
* Returns the root element of the component
|
|
@@ -144,7 +151,7 @@ class Component {
|
|
|
144
151
|
/**
|
|
145
152
|
* @typedef {typeof Component & ChildClass} ChildClassConstructor
|
|
146
153
|
*/
|
|
147
|
-
Component.elementType = HTMLElement;
|
|
154
|
+
Component.elementType = _self.HTMLElement;
|
|
148
155
|
|
|
149
156
|
const configOverride = Symbol.for('configOverride');
|
|
150
157
|
class ConfigurableComponent extends Component {
|
|
@@ -169,10 +176,14 @@ class ConfigurableComponent extends Component {
|
|
|
169
176
|
throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
|
|
170
177
|
}
|
|
171
178
|
const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
|
|
172
|
-
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}
|
|
179
|
+
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
|
|
180
|
+
this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
|
|
173
181
|
}
|
|
174
182
|
}
|
|
175
183
|
function normaliseString(value, property) {
|
|
184
|
+
if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
176
187
|
const trimmedValue = value ? value.trim() : '';
|
|
177
188
|
let output;
|
|
178
189
|
let outputType = property == null ? void 0 : property.type;
|
|
@@ -312,6 +323,17 @@ function extractConfigByNamespace(schema, dataset, namespace) {
|
|
|
312
323
|
* @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
|
|
313
324
|
*/
|
|
314
325
|
|
|
326
|
+
function createElement(tagName, attributes = {}, children = []) {
|
|
327
|
+
const $element = document.createElement(tagName);
|
|
328
|
+
Object.entries(attributes).forEach(([name, value]) => {
|
|
329
|
+
$element.setAttribute(name, value);
|
|
330
|
+
});
|
|
331
|
+
for (const child of children) {
|
|
332
|
+
$element.append(child);
|
|
333
|
+
}
|
|
334
|
+
return $element;
|
|
335
|
+
}
|
|
336
|
+
|
|
315
337
|
class I18n {
|
|
316
338
|
constructor(translations = {}, config = {}) {
|
|
317
339
|
var _config$locale;
|
|
@@ -402,6 +424,14 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
402
424
|
maxwords: undefined
|
|
403
425
|
};
|
|
404
426
|
}
|
|
427
|
+
if ('maxwords' in datasetConfig || this.config.maxwords !== undefined) {
|
|
428
|
+
console.warn(formatErrorMessage(CharacterCount, 'Option `maxwords` is deprecated. Use `maxlength` with `countType: "words"` instead.'));
|
|
429
|
+
if (!('maxlength' in datasetConfig)) {
|
|
430
|
+
var _datasetConfig$maxwor;
|
|
431
|
+
configOverrides.maxlength = (_datasetConfig$maxwor = datasetConfig.maxwords) != null ? _datasetConfig$maxwor : this.config.maxwords;
|
|
432
|
+
configOverrides.countType = 'words';
|
|
433
|
+
}
|
|
434
|
+
}
|
|
405
435
|
return configOverrides;
|
|
406
436
|
}
|
|
407
437
|
|
|
@@ -410,10 +440,11 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
410
440
|
* @param {CharacterCountConfig} [config] - Character count config
|
|
411
441
|
*/
|
|
412
442
|
constructor($root, config = {}) {
|
|
413
|
-
var
|
|
443
|
+
var _this$config$maxlengt;
|
|
414
444
|
super($root, config);
|
|
415
445
|
this.$textarea = void 0;
|
|
416
446
|
this.count = 0;
|
|
447
|
+
this.segmenter = null;
|
|
417
448
|
this.$visibleCountMessage = void 0;
|
|
418
449
|
this.$screenReaderCountMessage = void 0;
|
|
419
450
|
this.lastInputTimestamp = null;
|
|
@@ -437,7 +468,15 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
437
468
|
this.i18n = new I18n(this.config.i18n, {
|
|
438
469
|
locale: closestAttributeValue(this.$root, 'lang')
|
|
439
470
|
});
|
|
440
|
-
this.
|
|
471
|
+
if (this.config.countType === 'characters' || this.config.countType === 'words' && this.config.maxwords === undefined) {
|
|
472
|
+
if (!('Segmenter' in Intl)) {
|
|
473
|
+
throw new SupportError(formatErrorMessage(CharacterCount, 'Support for "Intl.Segmenter" required'));
|
|
474
|
+
}
|
|
475
|
+
this.segmenter = new Intl.Segmenter(this.i18n.locale, {
|
|
476
|
+
granularity: this.config.countType === 'words' ? 'word' : 'grapheme'
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
this.maxLength = (_this$config$maxlengt = this.config.maxlength) != null ? _this$config$maxlengt : Infinity;
|
|
441
480
|
this.$textarea = $textarea;
|
|
442
481
|
const textareaDescriptionId = `${this.$textarea.id}-info`;
|
|
443
482
|
const $textareaDescription = document.getElementById(textareaDescriptionId);
|
|
@@ -455,15 +494,16 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
455
494
|
});
|
|
456
495
|
}
|
|
457
496
|
this.$textarea.insertAdjacentElement('afterend', $textareaDescription);
|
|
458
|
-
const $screenReaderCountMessage =
|
|
459
|
-
|
|
460
|
-
|
|
497
|
+
const $screenReaderCountMessage = createElement('div', {
|
|
498
|
+
class: 'govuk-character-count__sr-status govuk-visually-hidden',
|
|
499
|
+
'aria-live': 'polite'
|
|
500
|
+
});
|
|
461
501
|
this.$screenReaderCountMessage = $screenReaderCountMessage;
|
|
462
502
|
$textareaDescription.insertAdjacentElement('afterend', $screenReaderCountMessage);
|
|
463
|
-
const $visibleCountMessage =
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
503
|
+
const $visibleCountMessage = createElement('div', {
|
|
504
|
+
class: `${$textareaDescription.className} govuk-character-count__status`,
|
|
505
|
+
'aria-hidden': 'true'
|
|
506
|
+
});
|
|
467
507
|
this.$visibleCountMessage = $visibleCountMessage;
|
|
468
508
|
$textareaDescription.insertAdjacentElement('afterend', $visibleCountMessage);
|
|
469
509
|
$textareaDescription.classList.add('govuk-visually-hidden');
|
|
@@ -531,26 +571,38 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
531
571
|
}
|
|
532
572
|
updateCount() {
|
|
533
573
|
const text = this.$textarea.value;
|
|
534
|
-
if (this.config.
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
574
|
+
if (this.config.countType === 'characters') {
|
|
575
|
+
this.count = this.segmenter ? Array.from(this.segmenter.segment(text)).length : 0;
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (this.config.countType === 'words') {
|
|
579
|
+
if (this.config.maxwords !== undefined) {
|
|
580
|
+
var _text$match$length, _text$match;
|
|
581
|
+
this.count = (_text$match$length = (_text$match = text.match(/\S+/g)) == null ? void 0 : _text$match.length) != null ? _text$match$length : 0;
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
const segments = this.segmenter ? Array.from(this.segmenter.segment(text)) : [];
|
|
585
|
+
this.count = segments.filter(segment => segment.isWordLike).length;
|
|
538
586
|
return;
|
|
539
587
|
}
|
|
540
588
|
this.count = text.length;
|
|
541
589
|
}
|
|
542
590
|
getCountMessage() {
|
|
543
591
|
const remainingNumber = this.maxLength - this.count;
|
|
544
|
-
|
|
545
|
-
return this.formatCountMessage(remainingNumber, countType);
|
|
592
|
+
return this.formatCountMessage(remainingNumber);
|
|
546
593
|
}
|
|
547
594
|
formatCountMessage(remainingNumber, countType) {
|
|
595
|
+
countType = countType != null ? countType : this.config.countType;
|
|
596
|
+
let translationKeyPrefix = 'characters';
|
|
597
|
+
let translationKeySuffix = remainingNumber < 0 ? 'OverLimit' : 'UnderLimit';
|
|
598
|
+
if (countType === 'words') {
|
|
599
|
+
translationKeyPrefix = 'words';
|
|
600
|
+
}
|
|
548
601
|
if (remainingNumber === 0) {
|
|
549
|
-
|
|
602
|
+
translationKeySuffix = 'AtLimit';
|
|
550
603
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
count: Math.abs(remainingNumber)
|
|
604
|
+
return this.i18n.t(`${translationKeyPrefix}${translationKeySuffix}`, {
|
|
605
|
+
count: remainingNumber === 0 ? undefined : Math.abs(remainingNumber)
|
|
554
606
|
});
|
|
555
607
|
}
|
|
556
608
|
isOverThreshold() {
|
|
@@ -569,13 +621,15 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
569
621
|
*
|
|
570
622
|
* @see {@link CharacterCount.defaults}
|
|
571
623
|
* @typedef {object} CharacterCountConfig
|
|
572
|
-
* @property {number} [maxlength] - The maximum number of characters
|
|
573
|
-
*
|
|
574
|
-
* @property {number} [maxwords] -
|
|
575
|
-
*
|
|
624
|
+
* @property {number} [maxlength] - The maximum number of characters (or words
|
|
625
|
+
* if `countType` is set to `"words"`).
|
|
626
|
+
* @property {number} [maxwords] - Deprecated. Use `maxlength` and
|
|
627
|
+
* `countType: "words"` instead.
|
|
576
628
|
* @property {number} [threshold=0] - The percentage value of the limit at
|
|
577
629
|
* which point the count message is displayed. If this attribute is set, the
|
|
578
630
|
* count message will be hidden by default.
|
|
631
|
+
* @property {'characters' | 'length' | 'words'} [countType] - The count type
|
|
632
|
+
* (`"characters"`, `"length"` or `"words"`) used to count the text.
|
|
579
633
|
* @property {CharacterCountTranslations} [i18n=CharacterCount.defaults.i18n] - Character count translations
|
|
580
634
|
*/
|
|
581
635
|
|
|
@@ -621,9 +675,9 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
621
675
|
* @property {TranslationPluralForms} [textareaDescription] - Message made
|
|
622
676
|
* available to assistive technologies, if none is already present in the
|
|
623
677
|
* HTML, to describe that the component accepts only a limited amount of
|
|
624
|
-
* content. It is visible on the page
|
|
625
|
-
* component will replace the `%{count}`
|
|
626
|
-
*
|
|
678
|
+
* content. It is visible on the page if `countType` is not supported or
|
|
679
|
+
* JavaScript is unavailable. The component will replace the `%{count}`
|
|
680
|
+
* placeholder with the value of the `maxlength` parameter.
|
|
627
681
|
*/
|
|
628
682
|
|
|
629
683
|
/**
|
|
@@ -633,6 +687,7 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
633
687
|
CharacterCount.moduleName = 'govuk-character-count';
|
|
634
688
|
CharacterCount.defaults = Object.freeze({
|
|
635
689
|
threshold: 0,
|
|
690
|
+
countType: 'length',
|
|
636
691
|
i18n: {
|
|
637
692
|
charactersUnderLimit: {
|
|
638
693
|
one: 'You have %{count} character remaining',
|
|
@@ -670,6 +725,9 @@ CharacterCount.schema = Object.freeze({
|
|
|
670
725
|
},
|
|
671
726
|
threshold: {
|
|
672
727
|
type: 'number'
|
|
728
|
+
},
|
|
729
|
+
countType: {
|
|
730
|
+
type: 'string'
|
|
673
731
|
}
|
|
674
732
|
},
|
|
675
733
|
anyOf: [{
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { closestAttributeValue } from '../../common/closest-attribute-value.mjs';
|
|
2
2
|
import { ConfigurableComponent, configOverride, validateConfig } from '../../common/configuration.mjs';
|
|
3
|
+
import { createElement } from '../../common/create-element.mjs';
|
|
3
4
|
import { formatErrorMessage } from '../../common/index.mjs';
|
|
4
|
-
import { ElementError, ConfigError } from '../../errors/index.mjs';
|
|
5
|
+
import { ElementError, ConfigError, SupportError } from '../../errors/index.mjs';
|
|
5
6
|
import { I18n } from '../../i18n.mjs';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -26,6 +27,14 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
26
27
|
maxwords: undefined
|
|
27
28
|
};
|
|
28
29
|
}
|
|
30
|
+
if ('maxwords' in datasetConfig || this.config.maxwords !== undefined) {
|
|
31
|
+
console.warn(formatErrorMessage(CharacterCount, 'Option `maxwords` is deprecated. Use `maxlength` with `countType: "words"` instead.'));
|
|
32
|
+
if (!('maxlength' in datasetConfig)) {
|
|
33
|
+
var _datasetConfig$maxwor;
|
|
34
|
+
configOverrides.maxlength = (_datasetConfig$maxwor = datasetConfig.maxwords) != null ? _datasetConfig$maxwor : this.config.maxwords;
|
|
35
|
+
configOverrides.countType = 'words';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
29
38
|
return configOverrides;
|
|
30
39
|
}
|
|
31
40
|
|
|
@@ -34,10 +43,11 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
34
43
|
* @param {CharacterCountConfig} [config] - Character count config
|
|
35
44
|
*/
|
|
36
45
|
constructor($root, config = {}) {
|
|
37
|
-
var
|
|
46
|
+
var _this$config$maxlengt;
|
|
38
47
|
super($root, config);
|
|
39
48
|
this.$textarea = void 0;
|
|
40
49
|
this.count = 0;
|
|
50
|
+
this.segmenter = null;
|
|
41
51
|
this.$visibleCountMessage = void 0;
|
|
42
52
|
this.$screenReaderCountMessage = void 0;
|
|
43
53
|
this.lastInputTimestamp = null;
|
|
@@ -61,7 +71,15 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
61
71
|
this.i18n = new I18n(this.config.i18n, {
|
|
62
72
|
locale: closestAttributeValue(this.$root, 'lang')
|
|
63
73
|
});
|
|
64
|
-
this.
|
|
74
|
+
if (this.config.countType === 'characters' || this.config.countType === 'words' && this.config.maxwords === undefined) {
|
|
75
|
+
if (!('Segmenter' in Intl)) {
|
|
76
|
+
throw new SupportError(formatErrorMessage(CharacterCount, 'Support for "Intl.Segmenter" required'));
|
|
77
|
+
}
|
|
78
|
+
this.segmenter = new Intl.Segmenter(this.i18n.locale, {
|
|
79
|
+
granularity: this.config.countType === 'words' ? 'word' : 'grapheme'
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
this.maxLength = (_this$config$maxlengt = this.config.maxlength) != null ? _this$config$maxlengt : Infinity;
|
|
65
83
|
this.$textarea = $textarea;
|
|
66
84
|
const textareaDescriptionId = `${this.$textarea.id}-info`;
|
|
67
85
|
const $textareaDescription = document.getElementById(textareaDescriptionId);
|
|
@@ -79,15 +97,16 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
79
97
|
});
|
|
80
98
|
}
|
|
81
99
|
this.$textarea.insertAdjacentElement('afterend', $textareaDescription);
|
|
82
|
-
const $screenReaderCountMessage =
|
|
83
|
-
|
|
84
|
-
|
|
100
|
+
const $screenReaderCountMessage = createElement('div', {
|
|
101
|
+
class: 'govuk-character-count__sr-status govuk-visually-hidden',
|
|
102
|
+
'aria-live': 'polite'
|
|
103
|
+
});
|
|
85
104
|
this.$screenReaderCountMessage = $screenReaderCountMessage;
|
|
86
105
|
$textareaDescription.insertAdjacentElement('afterend', $screenReaderCountMessage);
|
|
87
|
-
const $visibleCountMessage =
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
106
|
+
const $visibleCountMessage = createElement('div', {
|
|
107
|
+
class: `${$textareaDescription.className} govuk-character-count__status`,
|
|
108
|
+
'aria-hidden': 'true'
|
|
109
|
+
});
|
|
91
110
|
this.$visibleCountMessage = $visibleCountMessage;
|
|
92
111
|
$textareaDescription.insertAdjacentElement('afterend', $visibleCountMessage);
|
|
93
112
|
$textareaDescription.classList.add('govuk-visually-hidden');
|
|
@@ -155,26 +174,38 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
155
174
|
}
|
|
156
175
|
updateCount() {
|
|
157
176
|
const text = this.$textarea.value;
|
|
158
|
-
if (this.config.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
177
|
+
if (this.config.countType === 'characters') {
|
|
178
|
+
this.count = this.segmenter ? Array.from(this.segmenter.segment(text)).length : 0;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (this.config.countType === 'words') {
|
|
182
|
+
if (this.config.maxwords !== undefined) {
|
|
183
|
+
var _text$match$length, _text$match;
|
|
184
|
+
this.count = (_text$match$length = (_text$match = text.match(/\S+/g)) == null ? void 0 : _text$match.length) != null ? _text$match$length : 0;
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const segments = this.segmenter ? Array.from(this.segmenter.segment(text)) : [];
|
|
188
|
+
this.count = segments.filter(segment => segment.isWordLike).length;
|
|
162
189
|
return;
|
|
163
190
|
}
|
|
164
191
|
this.count = text.length;
|
|
165
192
|
}
|
|
166
193
|
getCountMessage() {
|
|
167
194
|
const remainingNumber = this.maxLength - this.count;
|
|
168
|
-
|
|
169
|
-
return this.formatCountMessage(remainingNumber, countType);
|
|
195
|
+
return this.formatCountMessage(remainingNumber);
|
|
170
196
|
}
|
|
171
197
|
formatCountMessage(remainingNumber, countType) {
|
|
198
|
+
countType = countType != null ? countType : this.config.countType;
|
|
199
|
+
let translationKeyPrefix = 'characters';
|
|
200
|
+
let translationKeySuffix = remainingNumber < 0 ? 'OverLimit' : 'UnderLimit';
|
|
201
|
+
if (countType === 'words') {
|
|
202
|
+
translationKeyPrefix = 'words';
|
|
203
|
+
}
|
|
172
204
|
if (remainingNumber === 0) {
|
|
173
|
-
|
|
205
|
+
translationKeySuffix = 'AtLimit';
|
|
174
206
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
count: Math.abs(remainingNumber)
|
|
207
|
+
return this.i18n.t(`${translationKeyPrefix}${translationKeySuffix}`, {
|
|
208
|
+
count: remainingNumber === 0 ? undefined : Math.abs(remainingNumber)
|
|
178
209
|
});
|
|
179
210
|
}
|
|
180
211
|
isOverThreshold() {
|
|
@@ -193,13 +224,15 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
193
224
|
*
|
|
194
225
|
* @see {@link CharacterCount.defaults}
|
|
195
226
|
* @typedef {object} CharacterCountConfig
|
|
196
|
-
* @property {number} [maxlength] - The maximum number of characters
|
|
197
|
-
*
|
|
198
|
-
* @property {number} [maxwords] -
|
|
199
|
-
*
|
|
227
|
+
* @property {number} [maxlength] - The maximum number of characters (or words
|
|
228
|
+
* if `countType` is set to `"words"`).
|
|
229
|
+
* @property {number} [maxwords] - Deprecated. Use `maxlength` and
|
|
230
|
+
* `countType: "words"` instead.
|
|
200
231
|
* @property {number} [threshold=0] - The percentage value of the limit at
|
|
201
232
|
* which point the count message is displayed. If this attribute is set, the
|
|
202
233
|
* count message will be hidden by default.
|
|
234
|
+
* @property {'characters' | 'length' | 'words'} [countType] - The count type
|
|
235
|
+
* (`"characters"`, `"length"` or `"words"`) used to count the text.
|
|
203
236
|
* @property {CharacterCountTranslations} [i18n=CharacterCount.defaults.i18n] - Character count translations
|
|
204
237
|
*/
|
|
205
238
|
|
|
@@ -245,9 +278,9 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
245
278
|
* @property {TranslationPluralForms} [textareaDescription] - Message made
|
|
246
279
|
* available to assistive technologies, if none is already present in the
|
|
247
280
|
* HTML, to describe that the component accepts only a limited amount of
|
|
248
|
-
* content. It is visible on the page
|
|
249
|
-
* component will replace the `%{count}`
|
|
250
|
-
*
|
|
281
|
+
* content. It is visible on the page if `countType` is not supported or
|
|
282
|
+
* JavaScript is unavailable. The component will replace the `%{count}`
|
|
283
|
+
* placeholder with the value of the `maxlength` parameter.
|
|
251
284
|
*/
|
|
252
285
|
|
|
253
286
|
/**
|
|
@@ -257,6 +290,7 @@ class CharacterCount extends ConfigurableComponent {
|
|
|
257
290
|
CharacterCount.moduleName = 'govuk-character-count';
|
|
258
291
|
CharacterCount.defaults = Object.freeze({
|
|
259
292
|
threshold: 0,
|
|
293
|
+
countType: 'length',
|
|
260
294
|
i18n: {
|
|
261
295
|
charactersUnderLimit: {
|
|
262
296
|
one: 'You have %{count} character remaining',
|
|
@@ -294,6 +328,9 @@ CharacterCount.schema = Object.freeze({
|
|
|
294
328
|
},
|
|
295
329
|
threshold: {
|
|
296
330
|
type: 'number'
|
|
331
|
+
},
|
|
332
|
+
countType: {
|
|
333
|
+
type: 'string'
|
|
297
334
|
}
|
|
298
335
|
},
|
|
299
336
|
anyOf: [{
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
function isObject(option) {
|
|
30
30
|
return !!option && typeof option === 'object' && !isArray(option);
|
|
31
31
|
}
|
|
32
|
+
function isScope($scope) {
|
|
33
|
+
return !!$scope && ($scope instanceof Element || $scope instanceof Document);
|
|
34
|
+
}
|
|
32
35
|
function formatErrorMessage(Component, message) {
|
|
33
36
|
return `${Component.moduleName}: ${message}`;
|
|
34
37
|
}
|
|
@@ -47,11 +50,14 @@
|
|
|
47
50
|
/**
|
|
48
51
|
* Checks if GOV.UK Frontend is supported on this page
|
|
49
52
|
*
|
|
50
|
-
* @param {
|
|
53
|
+
* @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
|
|
51
54
|
*/
|
|
52
|
-
constructor(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
constructor(scopeOrMessage = document.body) {
|
|
56
|
+
let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
|
|
57
|
+
if (!isScope(scopeOrMessage)) {
|
|
58
|
+
supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
|
|
59
|
+
}
|
|
60
|
+
super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
|
|
55
61
|
this.name = 'SupportError';
|
|
56
62
|
}
|
|
57
63
|
}
|
|
@@ -86,6 +92,7 @@
|
|
|
86
92
|
* @import { ComponentWithModuleName } from '../common/index.mjs'
|
|
87
93
|
*/
|
|
88
94
|
|
|
95
|
+
const _self = typeof globalThis !== 'undefined' ? globalThis : self;
|
|
89
96
|
class Component {
|
|
90
97
|
/**
|
|
91
98
|
* Returns the root element of the component
|
|
@@ -139,7 +146,7 @@
|
|
|
139
146
|
/**
|
|
140
147
|
* @typedef {typeof Component & ChildClass} ChildClassConstructor
|
|
141
148
|
*/
|
|
142
|
-
Component.elementType = HTMLElement;
|
|
149
|
+
Component.elementType = _self.HTMLElement;
|
|
143
150
|
|
|
144
151
|
/**
|
|
145
152
|
* Checkboxes component
|
|
@@ -23,6 +23,9 @@ function isArray(option) {
|
|
|
23
23
|
function isObject(option) {
|
|
24
24
|
return !!option && typeof option === 'object' && !isArray(option);
|
|
25
25
|
}
|
|
26
|
+
function isScope($scope) {
|
|
27
|
+
return !!$scope && ($scope instanceof Element || $scope instanceof Document);
|
|
28
|
+
}
|
|
26
29
|
function formatErrorMessage(Component, message) {
|
|
27
30
|
return `${Component.moduleName}: ${message}`;
|
|
28
31
|
}
|
|
@@ -41,11 +44,14 @@ class SupportError extends GOVUKFrontendError {
|
|
|
41
44
|
/**
|
|
42
45
|
* Checks if GOV.UK Frontend is supported on this page
|
|
43
46
|
*
|
|
44
|
-
* @param {
|
|
47
|
+
* @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
|
|
45
48
|
*/
|
|
46
|
-
constructor(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
constructor(scopeOrMessage = document.body) {
|
|
50
|
+
let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
|
|
51
|
+
if (!isScope(scopeOrMessage)) {
|
|
52
|
+
supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
|
|
53
|
+
}
|
|
54
|
+
super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
|
|
49
55
|
this.name = 'SupportError';
|
|
50
56
|
}
|
|
51
57
|
}
|
|
@@ -80,6 +86,7 @@ class InitError extends GOVUKFrontendError {
|
|
|
80
86
|
* @import { ComponentWithModuleName } from '../common/index.mjs'
|
|
81
87
|
*/
|
|
82
88
|
|
|
89
|
+
const _self = typeof globalThis !== 'undefined' ? globalThis : self;
|
|
83
90
|
class Component {
|
|
84
91
|
/**
|
|
85
92
|
* Returns the root element of the component
|
|
@@ -133,7 +140,7 @@ class Component {
|
|
|
133
140
|
/**
|
|
134
141
|
* @typedef {typeof Component & ChildClass} ChildClassConstructor
|
|
135
142
|
*/
|
|
136
|
-
Component.elementType = HTMLElement;
|
|
143
|
+
Component.elementType = _self.HTMLElement;
|
|
137
144
|
|
|
138
145
|
/**
|
|
139
146
|
* Checkboxes component
|
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
|
|
17
17
|
color: base.govuk-functional-colour(surface-text);
|
|
18
18
|
background-color: base.govuk-functional-colour(surface-background);
|
|
19
|
+
|
|
20
|
+
@media print {
|
|
21
|
+
border-bottom-color: currentcolor;
|
|
22
|
+
color: base.govuk-functional-colour(print-text);
|
|
23
|
+
background-color: transparent;
|
|
24
|
+
}
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
// Support older browsers which don't hide elements with the `hidden` attribute
|
data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js
CHANGED
|
@@ -53,6 +53,9 @@
|
|
|
53
53
|
function isObject(option) {
|
|
54
54
|
return !!option && typeof option === 'object' && !isArray(option);
|
|
55
55
|
}
|
|
56
|
+
function isScope($scope) {
|
|
57
|
+
return !!$scope && ($scope instanceof Element || $scope instanceof Document);
|
|
58
|
+
}
|
|
56
59
|
function formatErrorMessage(Component, message) {
|
|
57
60
|
return `${Component.moduleName}: ${message}`;
|
|
58
61
|
}
|
|
@@ -71,11 +74,14 @@
|
|
|
71
74
|
/**
|
|
72
75
|
* Checks if GOV.UK Frontend is supported on this page
|
|
73
76
|
*
|
|
74
|
-
* @param {
|
|
77
|
+
* @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
|
|
75
78
|
*/
|
|
76
|
-
constructor(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
constructor(scopeOrMessage = document.body) {
|
|
80
|
+
let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
|
|
81
|
+
if (!isScope(scopeOrMessage)) {
|
|
82
|
+
supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
|
|
83
|
+
}
|
|
84
|
+
super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
|
|
79
85
|
this.name = 'SupportError';
|
|
80
86
|
}
|
|
81
87
|
}
|
|
@@ -116,6 +122,7 @@
|
|
|
116
122
|
* @import { ComponentWithModuleName } from '../common/index.mjs'
|
|
117
123
|
*/
|
|
118
124
|
|
|
125
|
+
const _self = typeof globalThis !== 'undefined' ? globalThis : self;
|
|
119
126
|
class Component {
|
|
120
127
|
/**
|
|
121
128
|
* Returns the root element of the component
|
|
@@ -169,7 +176,7 @@
|
|
|
169
176
|
/**
|
|
170
177
|
* @typedef {typeof Component & ChildClass} ChildClassConstructor
|
|
171
178
|
*/
|
|
172
|
-
Component.elementType = HTMLElement;
|
|
179
|
+
Component.elementType = _self.HTMLElement;
|
|
173
180
|
|
|
174
181
|
const configOverride = Symbol.for('configOverride');
|
|
175
182
|
class ConfigurableComponent extends Component {
|
|
@@ -194,10 +201,14 @@
|
|
|
194
201
|
throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
|
|
195
202
|
}
|
|
196
203
|
const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
|
|
197
|
-
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}
|
|
204
|
+
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
|
|
205
|
+
this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
|
|
198
206
|
}
|
|
199
207
|
}
|
|
200
208
|
function normaliseString(value, property) {
|
|
209
|
+
if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
201
212
|
const trimmedValue = value ? value.trim() : '';
|
|
202
213
|
let output;
|
|
203
214
|
let outputType = property == null ? void 0 : property.type;
|
data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs
CHANGED
|
@@ -47,6 +47,9 @@ function isArray(option) {
|
|
|
47
47
|
function isObject(option) {
|
|
48
48
|
return !!option && typeof option === 'object' && !isArray(option);
|
|
49
49
|
}
|
|
50
|
+
function isScope($scope) {
|
|
51
|
+
return !!$scope && ($scope instanceof Element || $scope instanceof Document);
|
|
52
|
+
}
|
|
50
53
|
function formatErrorMessage(Component, message) {
|
|
51
54
|
return `${Component.moduleName}: ${message}`;
|
|
52
55
|
}
|
|
@@ -65,11 +68,14 @@ class SupportError extends GOVUKFrontendError {
|
|
|
65
68
|
/**
|
|
66
69
|
* Checks if GOV.UK Frontend is supported on this page
|
|
67
70
|
*
|
|
68
|
-
* @param {
|
|
71
|
+
* @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
|
|
69
72
|
*/
|
|
70
|
-
constructor(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
constructor(scopeOrMessage = document.body) {
|
|
74
|
+
let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
|
|
75
|
+
if (!isScope(scopeOrMessage)) {
|
|
76
|
+
supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
|
|
77
|
+
}
|
|
78
|
+
super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
|
|
73
79
|
this.name = 'SupportError';
|
|
74
80
|
}
|
|
75
81
|
}
|
|
@@ -110,6 +116,7 @@ class InitError extends GOVUKFrontendError {
|
|
|
110
116
|
* @import { ComponentWithModuleName } from '../common/index.mjs'
|
|
111
117
|
*/
|
|
112
118
|
|
|
119
|
+
const _self = typeof globalThis !== 'undefined' ? globalThis : self;
|
|
113
120
|
class Component {
|
|
114
121
|
/**
|
|
115
122
|
* Returns the root element of the component
|
|
@@ -163,7 +170,7 @@ class Component {
|
|
|
163
170
|
/**
|
|
164
171
|
* @typedef {typeof Component & ChildClass} ChildClassConstructor
|
|
165
172
|
*/
|
|
166
|
-
Component.elementType = HTMLElement;
|
|
173
|
+
Component.elementType = _self.HTMLElement;
|
|
167
174
|
|
|
168
175
|
const configOverride = Symbol.for('configOverride');
|
|
169
176
|
class ConfigurableComponent extends Component {
|
|
@@ -188,10 +195,14 @@ class ConfigurableComponent extends Component {
|
|
|
188
195
|
throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
|
|
189
196
|
}
|
|
190
197
|
const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
|
|
191
|
-
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}
|
|
198
|
+
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
|
|
199
|
+
this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
|
|
192
200
|
}
|
|
193
201
|
}
|
|
194
202
|
function normaliseString(value, property) {
|
|
203
|
+
if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
195
206
|
const trimmedValue = value ? value.trim() : '';
|
|
196
207
|
let output;
|
|
197
208
|
let outputType = property == null ? void 0 : property.type;
|