govuk_tech_docs 3.0.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of govuk_tech_docs might be problematic. Click here for more details.

Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +13 -0
  3. data/.github/pull_request_template.md +14 -1
  4. data/.github/workflows/publish.yaml +76 -0
  5. data/.github/workflows/test.yaml +23 -0
  6. data/CHANGELOG.md +30 -0
  7. data/lib/assets/javascripts/_modules/collapsible-navigation.js +13 -7
  8. data/lib/assets/javascripts/_modules/in-page-navigation.js +9 -4
  9. data/lib/assets/javascripts/_modules/search.js +11 -7
  10. data/lib/assets/stylesheets/_govuk_tech_docs.scss +1 -1
  11. data/lib/assets/stylesheets/modules/_anchored-heading.scss +2 -2
  12. data/lib/assets/stylesheets/modules/_search.scss +2 -2
  13. data/lib/assets/stylesheets/modules/_toc.scss +4 -4
  14. data/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +10 -0
  15. data/lib/govuk_tech_docs/api_reference/templates/api_reference_full.html.erb +2 -2
  16. data/lib/govuk_tech_docs/api_reference/templates/operation.html.erb +1 -1
  17. data/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb +1 -1
  18. data/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +1 -1
  19. data/lib/govuk_tech_docs/api_reference/templates/schema.html.erb +2 -2
  20. data/lib/govuk_tech_docs/contribution_banner.rb +8 -2
  21. data/lib/govuk_tech_docs/pages.rb +4 -2
  22. data/lib/govuk_tech_docs/path_helpers.rb +30 -0
  23. data/lib/govuk_tech_docs/table_of_contents/helpers.rb +7 -7
  24. data/lib/govuk_tech_docs/version.rb +1 -1
  25. data/lib/govuk_tech_docs.rb +1 -0
  26. data/lib/source/api/pages.json.erb +1 -1
  27. data/lib/source/layouts/_header.erb +3 -3
  28. data/lib/source/layouts/_search.erb +1 -1
  29. data/lib/source/layouts/core.erb +1 -1
  30. data/node_modules/govuk-frontend/govuk/all.js +272 -75
  31. data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +275 -98
  32. data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +169 -65
  33. data/node_modules/govuk-frontend/govuk/components/button/_index.scss +3 -4
  34. data/node_modules/govuk-frontend/govuk/components/button/button.js +2 -2
  35. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +3 -3
  36. data/node_modules/govuk-frontend/govuk/components/checkboxes/_index.scss +14 -0
  37. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +8 -10
  38. data/node_modules/govuk-frontend/govuk/components/cookie-banner/_index.scss +0 -2
  39. data/node_modules/govuk-frontend/govuk/components/details/_index.scss +2 -1
  40. data/node_modules/govuk-frontend/govuk/components/details/details.js +2 -2
  41. data/node_modules/govuk-frontend/govuk/components/error-message/_index.scss +1 -0
  42. data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +2 -2
  43. data/node_modules/govuk-frontend/govuk/components/file-upload/_index.scss +1 -0
  44. data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +6 -37
  45. data/node_modules/govuk-frontend/govuk/components/header/_index.scss +10 -4
  46. data/node_modules/govuk-frontend/govuk/components/header/header.js +4 -4
  47. data/node_modules/govuk-frontend/govuk/components/hint/_index.scss +1 -3
  48. data/node_modules/govuk-frontend/govuk/components/input/_index.scss +1 -1
  49. data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +499 -2
  50. data/node_modules/govuk-frontend/govuk/components/panel/_index.scss +13 -1
  51. data/node_modules/govuk-frontend/govuk/components/radios/_index.scss +14 -0
  52. data/node_modules/govuk-frontend/govuk/components/radios/radios.js +4 -4
  53. data/node_modules/govuk-frontend/govuk/components/select/_index.scss +1 -1
  54. data/node_modules/govuk-frontend/govuk/components/skip-link/_index.scss +13 -0
  55. data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +1108 -0
  56. data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +15 -23
  57. data/node_modules/govuk-frontend/govuk/components/tabs/_index.scss +2 -2
  58. data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +2 -2
  59. data/node_modules/govuk-frontend/govuk/components/tag/_index.scss +0 -5
  60. data/node_modules/govuk-frontend/govuk/components/textarea/_index.scss +1 -1
  61. data/node_modules/govuk-frontend/govuk/core/_all.scss +0 -1
  62. data/node_modules/govuk-frontend/govuk/core/_global-styles.scss +0 -6
  63. data/node_modules/govuk-frontend/govuk/core/_links.scss +0 -6
  64. data/node_modules/govuk-frontend/govuk/core/_lists.scss +0 -6
  65. data/node_modules/govuk-frontend/govuk/core/_section-break.scss +0 -6
  66. data/node_modules/govuk-frontend/govuk/core/_typography.scss +0 -6
  67. data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +2 -2
  68. data/node_modules/govuk-frontend/govuk/helpers/_spacing.scss +22 -4
  69. data/node_modules/govuk-frontend/govuk/objects/_all.scss +1 -0
  70. data/node_modules/govuk-frontend/govuk/objects/_main-wrapper.scss +15 -30
  71. data/node_modules/govuk-frontend/govuk/{core → objects}/_template.scss +1 -5
  72. data/node_modules/govuk-frontend/govuk/overrides/_all.scss +1 -0
  73. data/node_modules/govuk-frontend/govuk/overrides/_display.scss +0 -6
  74. data/node_modules/govuk-frontend/govuk/overrides/_spacing.scss +0 -6
  75. data/node_modules/govuk-frontend/govuk/overrides/_text-align.scss +14 -0
  76. data/node_modules/govuk-frontend/govuk/overrides/_typography.scss +0 -6
  77. data/node_modules/govuk-frontend/govuk/overrides/_width.scss +0 -6
  78. data/node_modules/govuk-frontend/govuk/settings/_colours-organisations.scss +3 -0
  79. data/node_modules/govuk-frontend/govuk/settings/_measurements.scss +0 -10
  80. data/node_modules/govuk-frontend/govuk/tools/_all.scss +0 -1
  81. data/package-lock.json +6 -6
  82. data/package.json +1 -1
  83. metadata +13 -9
  84. data/.travis.yml +0 -19
  85. data/node_modules/govuk-frontend/govuk/tools/_iff.scss +0 -17
@@ -1,7 +1,7 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define('GOVUKFrontend', factory) :
4
- (global.GOVUKFrontend = factory());
3
+ typeof define === 'function' && define.amd ? define('GOVUKFrontend.Accordion', factory) :
4
+ (global.GOVUKFrontend = global.GOVUKFrontend || {}, global.GOVUKFrontend.Accordion = factory());
5
5
  }(this, (function () { 'use strict';
6
6
 
7
7
  /**
@@ -762,19 +762,28 @@ function Accordion ($module) {
762
762
  this.$module = $module;
763
763
  this.moduleId = $module.getAttribute('id');
764
764
  this.$sections = $module.querySelectorAll('.govuk-accordion__section');
765
- this.$openAllButton = '';
765
+ this.$showAllButton = '';
766
766
  this.browserSupportsSessionStorage = helper.checkForSessionStorage();
767
767
 
768
768
  this.controlsClass = 'govuk-accordion__controls';
769
- this.openAllClass = 'govuk-accordion__open-all';
770
- this.iconClass = 'govuk-accordion__icon';
769
+ this.showAllClass = 'govuk-accordion__show-all';
770
+ this.showAllTextClass = 'govuk-accordion__show-all-text';
771
771
 
772
+ this.sectionExpandedClass = 'govuk-accordion__section--expanded';
773
+ this.sectionButtonClass = 'govuk-accordion__section-button';
772
774
  this.sectionHeaderClass = 'govuk-accordion__section-header';
773
- this.sectionHeaderFocusedClass = 'govuk-accordion__section-header--focused';
774
775
  this.sectionHeadingClass = 'govuk-accordion__section-heading';
776
+ this.sectionHeadingTextClass = 'govuk-accordion__section-heading-text';
777
+ this.sectionHeadingTextFocusClass = 'govuk-accordion__section-heading-text-focus';
778
+
779
+ this.sectionShowHideToggleClass = 'govuk-accordion__section-toggle';
780
+ this.sectionShowHideToggleFocusClass = 'govuk-accordion__section-toggle-focus';
781
+ this.sectionShowHideTextClass = 'govuk-accordion__section-toggle-text';
782
+ this.upChevronIconClass = 'govuk-accordion-nav__chevron';
783
+ this.downChevronIconClass = 'govuk-accordion-nav__chevron--down';
784
+
775
785
  this.sectionSummaryClass = 'govuk-accordion__section-summary';
776
- this.sectionButtonClass = 'govuk-accordion__section-button';
777
- this.sectionExpandedClass = 'govuk-accordion__section--expanded';
786
+ this.sectionSummaryFocusClass = 'govuk-accordion__section-summary-focus';
778
787
  }
779
788
 
780
789
  // Initialize component
@@ -785,32 +794,39 @@ Accordion.prototype.init = function () {
785
794
  }
786
795
 
787
796
  this.initControls();
788
-
789
797
  this.initSectionHeaders();
790
798
 
791
- // See if "Open all" button text should be updated
799
+ // See if "Show all sections" button text should be updated
792
800
  var areAllSectionsOpen = this.checkIfAllSectionsOpen();
793
- this.updateOpenAllButton(areAllSectionsOpen);
801
+ this.updateShowAllButton(areAllSectionsOpen);
794
802
  };
795
803
 
796
804
  // Initialise controls and set attributes
797
805
  Accordion.prototype.initControls = function () {
798
- // Create "Open all" button and set attributes
799
- this.$openAllButton = document.createElement('button');
800
- this.$openAllButton.setAttribute('type', 'button');
801
- this.$openAllButton.innerHTML = 'Open all <span class="govuk-visually-hidden">sections</span>';
802
- this.$openAllButton.setAttribute('class', this.openAllClass);
803
- this.$openAllButton.setAttribute('aria-expanded', 'false');
804
- this.$openAllButton.setAttribute('type', 'button');
806
+ // Create "Show all" button and set attributes
807
+ this.$showAllButton = document.createElement('button');
808
+ this.$showAllButton.setAttribute('type', 'button');
809
+ this.$showAllButton.setAttribute('class', this.showAllClass);
810
+ this.$showAllButton.setAttribute('aria-expanded', 'false');
805
811
 
806
- // Create control wrapper and add controls to it
807
- var accordionControls = document.createElement('div');
808
- accordionControls.setAttribute('class', this.controlsClass);
809
- accordionControls.appendChild(this.$openAllButton);
810
- this.$module.insertBefore(accordionControls, this.$module.firstChild);
812
+ // Create icon, add to element
813
+ var $icon = document.createElement('span');
814
+ $icon.classList.add(this.upChevronIconClass);
815
+ this.$showAllButton.appendChild($icon);
811
816
 
812
- // Handle events for the controls
813
- this.$openAllButton.addEventListener('click', this.onOpenOrCloseAllToggle.bind(this));
817
+ // Create control wrapper and add controls to it
818
+ var $accordionControls = document.createElement('div');
819
+ $accordionControls.setAttribute('class', this.controlsClass);
820
+ $accordionControls.appendChild(this.$showAllButton);
821
+ this.$module.insertBefore($accordionControls, this.$module.firstChild);
822
+
823
+ // Build additional wrapper for Show all toggle text and place after icon
824
+ var $wrappershowAllText = document.createElement('span');
825
+ $wrappershowAllText.classList.add(this.showAllTextClass);
826
+ this.$showAllButton.appendChild($wrappershowAllText);
827
+
828
+ // Handle click events on the show/hide all button
829
+ this.$showAllButton.addEventListener('click', this.onShowOrHideAllToggle.bind(this));
814
830
  };
815
831
 
816
832
  // Initialise section headers
@@ -818,13 +834,12 @@ Accordion.prototype.initSectionHeaders = function () {
818
834
  // Loop through section headers
819
835
  nodeListForEach(this.$sections, function ($section, i) {
820
836
  // Set header attributes
821
- var header = $section.querySelector('.' + this.sectionHeaderClass);
822
- this.initHeaderAttributes(header, i);
823
-
837
+ var $header = $section.querySelector('.' + this.sectionHeaderClass);
838
+ this.constructHeaderMarkup($header, i);
824
839
  this.setExpanded(this.isExpanded($section), $section);
825
840
 
826
841
  // Handle events
827
- header.addEventListener('click', this.onSectionToggle.bind(this, $section));
842
+ $header.addEventListener('click', this.onSectionToggle.bind(this, $section));
828
843
 
829
844
  // See if there is any state stored in sessionStorage and set the sections to
830
845
  // open or closed.
@@ -832,51 +847,100 @@ Accordion.prototype.initSectionHeaders = function () {
832
847
  }.bind(this));
833
848
  };
834
849
 
835
- // Set individual header attributes
836
- Accordion.prototype.initHeaderAttributes = function ($headerWrapper, index) {
837
- var $module = this;
850
+ Accordion.prototype.constructHeaderMarkup = function ($headerWrapper, index) {
838
851
  var $span = $headerWrapper.querySelector('.' + this.sectionButtonClass);
839
852
  var $heading = $headerWrapper.querySelector('.' + this.sectionHeadingClass);
840
853
  var $summary = $headerWrapper.querySelector('.' + this.sectionSummaryClass);
841
854
 
842
- // Copy existing span element to an actual button element, for improved accessibility.
855
+ // Create a button element that will replace the '.govuk-accordion__section-button' span
843
856
  var $button = document.createElement('button');
844
857
  $button.setAttribute('type', 'button');
845
- $button.setAttribute('id', this.moduleId + '-heading-' + (index + 1));
846
858
  $button.setAttribute('aria-controls', this.moduleId + '-content-' + (index + 1));
847
859
 
848
860
  // Copy all attributes (https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes) from $span to $button
849
861
  for (var i = 0; i < $span.attributes.length; i++) {
850
862
  var attr = $span.attributes.item(i);
851
- $button.setAttribute(attr.nodeName, attr.nodeValue);
863
+ // Add all attributes but not ID as this is being added to
864
+ // the section heading ($headingText)
865
+ if (attr.nodeName !== 'id') {
866
+ $button.setAttribute(attr.nodeName, attr.nodeValue);
867
+ }
852
868
  }
853
869
 
854
- $button.addEventListener('focusin', function (e) {
855
- if (!$headerWrapper.classList.contains($module.sectionHeaderFocusedClass)) {
856
- $headerWrapper.className += ' ' + $module.sectionHeaderFocusedClass;
870
+ // Create container for heading text so it can be styled
871
+ var $headingText = document.createElement('span');
872
+ $headingText.classList.add(this.sectionHeadingTextClass);
873
+ // Copy the span ID to the heading text to allow it to be referenced by `aria-labelledby` on the
874
+ // hidden content area without "Show this section"
875
+ $headingText.id = $span.id;
876
+
877
+ // Create an inner heading text container to limit the width of the focus state
878
+ var $headingTextFocus = document.createElement('span');
879
+ $headingTextFocus.classList.add(this.sectionHeadingTextFocusClass);
880
+ $headingText.appendChild($headingTextFocus);
881
+ // span could contain HTML elements (see https://www.w3.org/TR/2011/WD-html5-20110525/content-models.html#phrasing-content)
882
+ $headingTextFocus.innerHTML = $span.innerHTML;
883
+
884
+ // Create container for show / hide icons and text.
885
+ var $showToggle = document.createElement('span');
886
+ $showToggle.classList.add(this.sectionShowHideToggleClass);
887
+ // Tell Google not to index the 'show' text as part of the heading
888
+ // For the snippet to work with JavaScript, it must be added before adding the page element to the
889
+ // page's DOM. See https://developers.google.com/search/docs/advanced/robots/robots_meta_tag#data-nosnippet-attr
890
+ $showToggle.setAttribute('data-nosnippet', '');
891
+ // Create an inner container to limit the width of the focus state
892
+ var $showToggleFocus = document.createElement('span');
893
+ $showToggleFocus.classList.add(this.sectionShowHideToggleFocusClass);
894
+ $showToggle.appendChild($showToggleFocus);
895
+ // Create wrapper for the show / hide text. Append text after the show/hide icon
896
+ var $showToggleText = document.createElement('span');
897
+ var $icon = document.createElement('span');
898
+ $icon.classList.add(this.upChevronIconClass);
899
+ $showToggleFocus.appendChild($icon);
900
+ $showToggleText.classList.add(this.sectionShowHideTextClass);
901
+ $showToggleFocus.appendChild($showToggleText);
902
+
903
+ // Append elements to the button:
904
+ // 1. Heading text
905
+ // 2. Punctuation
906
+ // 3. (Optional: Summary line followed by punctuation)
907
+ // 4. Show / hide toggle
908
+ $button.appendChild($headingText);
909
+ $button.appendChild(this.getButtonPunctuationEl());
910
+
911
+ // If summary content exists add to DOM in correct order
912
+ if (typeof ($summary) !== 'undefined' && $summary !== null) {
913
+ // Create a new `span` element and copy the summary line content from the original `div` to the
914
+ // new `span`
915
+ // This is because the summary line text is now inside a button element, which can only contain
916
+ // phrasing content
917
+ var $summarySpan = document.createElement('span');
918
+ // Create an inner summary container to limit the width of the summary focus state
919
+ var $summarySpanFocus = document.createElement('span');
920
+ $summarySpanFocus.classList.add(this.sectionSummaryFocusClass);
921
+ $summarySpan.appendChild($summarySpanFocus);
922
+
923
+ // Get original attributes, and pass them to the replacement
924
+ for (var j = 0, l = $summary.attributes.length; j < l; ++j) {
925
+ var nodeName = $summary.attributes.item(j).nodeName;
926
+ var nodeValue = $summary.attributes.item(j).nodeValue;
927
+ $summarySpan.setAttribute(nodeName, nodeValue);
857
928
  }
858
- });
859
929
 
860
- $button.addEventListener('blur', function (e) {
861
- $headerWrapper.classList.remove($module.sectionHeaderFocusedClass);
862
- });
930
+ // Copy original contents of summary to the new summary span
931
+ $summarySpanFocus.innerHTML = $summary.innerHTML;
863
932
 
864
- if (typeof ($summary) !== 'undefined' && $summary !== null) {
865
- $button.setAttribute('aria-describedby', this.moduleId + '-summary-' + (index + 1));
933
+ // Replace the original summary `div` with the new summary `span`
934
+ $summary.parentNode.replaceChild($summarySpan, $summary);
935
+
936
+ $button.appendChild($summarySpan);
937
+ $button.appendChild(this.getButtonPunctuationEl());
866
938
  }
867
939
 
868
- // $span could contain HTML elements (see https://www.w3.org/TR/2011/WD-html5-20110525/content-models.html#phrasing-content)
869
- $button.innerHTML = $span.innerHTML;
940
+ $button.appendChild($showToggle);
870
941
 
871
942
  $heading.removeChild($span);
872
943
  $heading.appendChild($button);
873
-
874
- // Add "+/-" icon
875
- var icon = document.createElement('span');
876
- icon.className = this.iconClass;
877
- icon.setAttribute('aria-hidden', 'true');
878
-
879
- $button.appendChild(icon);
880
944
  };
881
945
 
882
946
  // When section toggled, set and store state
@@ -889,10 +953,9 @@ Accordion.prototype.onSectionToggle = function ($section) {
889
953
  };
890
954
 
891
955
  // When Open/Close All toggled, set and store state
892
- Accordion.prototype.onOpenOrCloseAllToggle = function () {
956
+ Accordion.prototype.onShowOrHideAllToggle = function () {
893
957
  var $module = this;
894
958
  var $sections = this.$sections;
895
-
896
959
  var nowExpanded = !this.checkIfAllSectionsOpen();
897
960
 
898
961
  nodeListForEach($sections, function ($section) {
@@ -901,23 +964,37 @@ Accordion.prototype.onOpenOrCloseAllToggle = function () {
901
964
  $module.storeState($section);
902
965
  });
903
966
 
904
- $module.updateOpenAllButton(nowExpanded);
967
+ $module.updateShowAllButton(nowExpanded);
905
968
  };
906
969
 
907
970
  // Set section attributes when opened/closed
908
971
  Accordion.prototype.setExpanded = function (expanded, $section) {
972
+ var $icon = $section.querySelector('.' + this.upChevronIconClass);
973
+ var $showHideText = $section.querySelector('.' + this.sectionShowHideTextClass);
909
974
  var $button = $section.querySelector('.' + this.sectionButtonClass);
975
+ var $newButtonText = expanded ? 'Hide' : 'Show';
976
+
977
+ // Build additional copy of "this section" for assistive technology and place inside toggle link
978
+ var $visuallyHiddenText = document.createElement('span');
979
+ $visuallyHiddenText.classList.add('govuk-visually-hidden');
980
+ $visuallyHiddenText.innerHTML = ' this section';
981
+
982
+ $showHideText.innerHTML = $newButtonText;
983
+ $showHideText.appendChild($visuallyHiddenText);
910
984
  $button.setAttribute('aria-expanded', expanded);
911
985
 
986
+ // Swap icon, change class
912
987
  if (expanded) {
913
988
  $section.classList.add(this.sectionExpandedClass);
989
+ $icon.classList.remove(this.downChevronIconClass);
914
990
  } else {
915
991
  $section.classList.remove(this.sectionExpandedClass);
992
+ $icon.classList.add(this.downChevronIconClass);
916
993
  }
917
994
 
918
- // See if "Open all" button text should be updated
995
+ // See if "Show all sections" button text should be updated
919
996
  var areAllSectionsOpen = this.checkIfAllSectionsOpen();
920
- this.updateOpenAllButton(areAllSectionsOpen);
997
+ this.updateShowAllButton(areAllSectionsOpen);
921
998
  };
922
999
 
923
1000
  // Get state of section
@@ -936,12 +1013,20 @@ Accordion.prototype.checkIfAllSectionsOpen = function () {
936
1013
  return areAllSectionsOpen
937
1014
  };
938
1015
 
939
- // Update "Open all" button
940
- Accordion.prototype.updateOpenAllButton = function (expanded) {
941
- var newButtonText = expanded ? 'Close all' : 'Open all';
942
- newButtonText += '<span class="govuk-visually-hidden"> sections</span>';
943
- this.$openAllButton.setAttribute('aria-expanded', expanded);
944
- this.$openAllButton.innerHTML = newButtonText;
1016
+ // Update "Show all sections" button
1017
+ Accordion.prototype.updateShowAllButton = function (expanded) {
1018
+ var $showAllIcon = this.$showAllButton.querySelector('.' + this.upChevronIconClass);
1019
+ var $showAllText = this.$showAllButton.querySelector('.' + this.showAllTextClass);
1020
+ var newButtonText = expanded ? 'Hide all sections' : 'Show all sections';
1021
+ this.$showAllButton.setAttribute('aria-expanded', expanded);
1022
+ $showAllText.innerHTML = newButtonText;
1023
+
1024
+ // Swap icon, toggle class
1025
+ if (expanded) {
1026
+ $showAllIcon.classList.remove(this.downChevronIconClass);
1027
+ } else {
1028
+ $showAllIcon.classList.add(this.downChevronIconClass);
1029
+ }
945
1030
  };
946
1031
 
947
1032
  // Check for `window.sessionStorage`, and that it actually works.
@@ -965,7 +1050,7 @@ var helper = {
965
1050
  // Set the state of the accordions in sessionStorage
966
1051
  Accordion.prototype.storeState = function ($section) {
967
1052
  if (this.browserSupportsSessionStorage) {
968
- // We need a unique way of identifying each content in the accordion. Since
1053
+ // We need a unique way of identifying each content in the Accordion. Since
969
1054
  // an `#id` should be unique and an `id` is required for `aria-` attributes
970
1055
  // `id` can be safely used.
971
1056
  var $button = $section.querySelector('.' + this.sectionButtonClass);
@@ -1006,6 +1091,25 @@ Accordion.prototype.setInitialState = function ($section) {
1006
1091
  }
1007
1092
  };
1008
1093
 
1094
+ /**
1095
+ * Create an element to improve semantics of the section button with punctuation
1096
+ * @return {object} DOM element
1097
+ *
1098
+ * Used to add pause (with a comma) for assistive technology.
1099
+ * Example: [heading]Section A ,[pause] Show this section.
1100
+ * https://accessibility.blog.gov.uk/2017/12/18/what-working-on-gov-uk-navigation-taught-us-about-accessibility/
1101
+ *
1102
+ * Adding punctuation to the button can also improve its general semantics by dividing its contents
1103
+ * into thematic chunks.
1104
+ * See https://github.com/alphagov/govuk-frontend/issues/2327#issuecomment-922957442
1105
+ */
1106
+ Accordion.prototype.getButtonPunctuationEl = function () {
1107
+ var $punctuationEl = document.createElement('span');
1108
+ $punctuationEl.classList.add('govuk-visually-hidden', 'govuk-accordion__section-heading-divider');
1109
+ $punctuationEl.innerHTML = ', ';
1110
+ return $punctuationEl
1111
+ };
1112
+
1009
1113
  return Accordion;
1010
1114
 
1011
1115
  })));
@@ -158,10 +158,6 @@
158
158
  cursor: default;
159
159
  }
160
160
 
161
- &:focus {
162
- outline: none;
163
- }
164
-
165
161
  &:active {
166
162
  top: 0;
167
163
  box-shadow: 0 $button-shadow-size 0 $govuk-button-shadow-colour; // s0
@@ -270,6 +266,9 @@
270
266
  -webkit-align-self: center;
271
267
  -ms-flex-item-align: center;
272
268
  align-self: center;
269
+ // Work around SVGs not inheriting color from parent in forced color mode
270
+ // (https://github.com/w3c/csswg-drafts/issues/6310)
271
+ forced-color-adjust: auto;
273
272
  }
274
273
 
275
274
  @if $govuk-use-legacy-font {
@@ -1,7 +1,7 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define('GOVUKFrontend', factory) :
4
- (global.GOVUKFrontend = factory());
3
+ typeof define === 'function' && define.amd ? define('GOVUKFrontend.Button', factory) :
4
+ (global.GOVUKFrontend = global.GOVUKFrontend || {}, global.GOVUKFrontend.Button = factory());
5
5
  }(this, (function () { 'use strict';
6
6
 
7
7
  (function(undefined) {
@@ -1,7 +1,7 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define('GOVUKFrontend', factory) :
4
- (global.GOVUKFrontend = factory());
3
+ typeof define === 'function' && define.amd ? define('GOVUKFrontend.CharacterCount', factory) :
4
+ (global.GOVUKFrontend = global.GOVUKFrontend || {}, global.GOVUKFrontend.CharacterCount = factory());
5
5
  }(this, (function () { 'use strict';
6
6
 
7
7
  (function(undefined) {
@@ -1018,7 +1018,7 @@ function CharacterCount ($module) {
1018
1018
  this.$module = $module;
1019
1019
  this.$textarea = $module.querySelector('.govuk-js-character-count');
1020
1020
  if (this.$textarea) {
1021
- this.$countMessage = $module.querySelector('[id="' + this.$textarea.id + '-info"]');
1021
+ this.$countMessage = document.getElementById(this.$textarea.id + '-info');
1022
1022
  }
1023
1023
  }
1024
1024
 
@@ -127,6 +127,20 @@
127
127
  // Focused state
128
128
  .govuk-checkboxes__input:focus + .govuk-checkboxes__label:before {
129
129
  border-width: 4px;
130
+
131
+ // When colours are overridden, the yellow box-shadow becomes invisible
132
+ // which means the focus state is less obvious. By adding a transparent
133
+ // outline, which becomes solid (text-coloured) in that context, we ensure
134
+ // the focus remains clearly visible.
135
+ outline: $govuk-focus-width solid transparent;
136
+ outline-offset: 1px;
137
+
138
+ // When in an explicit forced-color mode, we can use the Highlight system
139
+ // color for the outline to better match focus states of native controls
140
+ @media screen and (forced-colors: active), (-ms-high-contrast: active) {
141
+ outline-color: Highlight;
142
+ }
143
+
130
144
  box-shadow: 0 0 0 $govuk-focus-width $govuk-focus-colour;
131
145
  }
132
146
 
@@ -1,7 +1,7 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define('GOVUKFrontend', factory) :
4
- (global.GOVUKFrontend = factory());
3
+ typeof define === 'function' && define.amd ? define('GOVUKFrontend.Checkboxes', factory) :
4
+ (global.GOVUKFrontend = global.GOVUKFrontend || {}, global.GOVUKFrontend.Checkboxes = factory());
5
5
  }(this, (function () { 'use strict';
6
6
 
7
7
  (function(undefined) {
@@ -1056,7 +1056,7 @@ Checkboxes.prototype.init = function () {
1056
1056
 
1057
1057
  // Skip checkboxes without data-aria-controls attributes, or where the
1058
1058
  // target element does not exist.
1059
- if (!target || !$module.querySelector('#' + target)) {
1059
+ if (!target || !document.getElementById(target)) {
1060
1060
  return
1061
1061
  }
1062
1062
 
@@ -1100,7 +1100,7 @@ Checkboxes.prototype.syncAllConditionalReveals = function () {
1100
1100
  * @param {HTMLInputElement} $input Checkbox input
1101
1101
  */
1102
1102
  Checkboxes.prototype.syncConditionalRevealWithInputState = function ($input) {
1103
- var $target = this.$module.querySelector('#' + $input.getAttribute('aria-controls'));
1103
+ var $target = document.getElementById($input.getAttribute('aria-controls'));
1104
1104
 
1105
1105
  if ($target && $target.classList.contains('govuk-checkboxes__conditional')) {
1106
1106
  var inputIsChecked = $input.checked;
@@ -1123,10 +1123,9 @@ Checkboxes.prototype.unCheckAllInputsExcept = function ($input) {
1123
1123
  var hasSameFormOwner = ($input.form === $inputWithSameName.form);
1124
1124
  if (hasSameFormOwner && $inputWithSameName !== $input) {
1125
1125
  $inputWithSameName.checked = false;
1126
+ this.syncConditionalRevealWithInputState($inputWithSameName);
1126
1127
  }
1127
- });
1128
-
1129
- this.syncAllConditionalReveals();
1128
+ }.bind(this));
1130
1129
  };
1131
1130
 
1132
1131
  /**
@@ -1145,10 +1144,9 @@ Checkboxes.prototype.unCheckExclusiveInputs = function ($input) {
1145
1144
  var hasSameFormOwner = ($input.form === $exclusiveInput.form);
1146
1145
  if (hasSameFormOwner) {
1147
1146
  $exclusiveInput.checked = false;
1147
+ this.syncConditionalRevealWithInputState($exclusiveInput);
1148
1148
  }
1149
- });
1150
-
1151
- this.syncAllConditionalReveals();
1149
+ }.bind(this));
1152
1150
  };
1153
1151
 
1154
1152
  /**
@@ -4,8 +4,6 @@
4
4
  $border-bottom-width: govuk-spacing(2);
5
5
 
6
6
  .govuk-cookie-banner {
7
- @include govuk-font($size: 19);
8
-
9
7
  padding-top: govuk-spacing(4);
10
8
  // The component does not set bottom spacing.
11
9
  // The bottom spacing should be created by the items inside the component.
@@ -71,7 +71,8 @@
71
71
  }
72
72
 
73
73
  .govuk-details__text {
74
- padding: govuk-spacing(3);
74
+ padding-top: govuk-spacing(3);
75
+ padding-bottom: govuk-spacing(3);
75
76
  padding-left: govuk-spacing(4);
76
77
  border-left: $govuk-border-width solid $govuk-border-colour;
77
78
  }
@@ -1,7 +1,7 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define('GOVUKFrontend', factory) :
4
- (global.GOVUKFrontend = factory());
3
+ typeof define === 'function' && define.amd ? define('GOVUKFrontend.Details', factory) :
4
+ (global.GOVUKFrontend = global.GOVUKFrontend || {}, global.GOVUKFrontend.Details = factory());
5
5
  }(this, (function () { 'use strict';
6
6
 
7
7
  (function(undefined) {
@@ -3,6 +3,7 @@
3
3
  @include govuk-font($size: 19, $weight: bold);
4
4
 
5
5
  display: block;
6
+ margin-top: 0; // Reset any default browser margins for paragraphs
6
7
  margin-bottom: govuk-spacing(3);
7
8
  clear: both;
8
9
 
@@ -1,7 +1,7 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define('GOVUKFrontend', factory) :
4
- (global.GOVUKFrontend = factory());
3
+ typeof define === 'function' && define.amd ? define('GOVUKFrontend.ErrorSummary', factory) :
4
+ (global.GOVUKFrontend = global.GOVUKFrontend || {}, global.GOVUKFrontend.ErrorSummary = factory());
5
5
  }(this, (function () { 'use strict';
6
6
 
7
7
  (function(undefined) {
@@ -8,6 +8,7 @@
8
8
  .govuk-file-upload {
9
9
  @include govuk-font($size: 19);
10
10
  @include govuk-text-colour;
11
+ max-width: 100%;
11
12
  margin-left: -$component-padding;
12
13
  padding: $component-padding;
13
14
 
@@ -111,6 +111,9 @@
111
111
  margin-bottom: govuk-spacing(3);
112
112
  }
113
113
  vertical-align: top;
114
+ // Work around SVGs not inheriting color from parent in forced color mode
115
+ // (https://github.com/w3c/csswg-drafts/issues/6310)
116
+ forced-color-adjust: auto;
114
117
  }
115
118
 
116
119
  .govuk-footer__licence-description {
@@ -149,8 +152,9 @@
149
152
  }
150
153
 
151
154
  .govuk-footer__heading {
152
- @include govuk-responsive-margin(7, "bottom");
155
+ margin-bottom: govuk-spacing(6);
153
156
  padding-bottom: govuk-spacing(4);
157
+
154
158
  @include govuk-media-query ($until: tablet) {
155
159
  padding-bottom: govuk-spacing(2);
156
160
  }
@@ -158,50 +162,15 @@
158
162
  }
159
163
 
160
164
  .govuk-footer__navigation {
161
- display: -webkit-box;
162
- display: -webkit-flex;
163
- display: -ms-flexbox;
164
- display: flex; // Support: Flexbox
165
+ @include govuk-clearfix;
165
166
  margin-right: -$govuk-gutter-half;
166
167
  margin-left: -$govuk-gutter-half;
167
- -webkit-flex-wrap: wrap;
168
- -ms-flex-wrap: wrap;
169
- flex-wrap: wrap; // Support: Flexbox
170
168
  }
171
169
 
172
170
  .govuk-footer__section {
173
171
  display: inline-block;
174
- margin-right: $govuk-gutter-half;
175
172
  margin-bottom: $govuk-gutter;
176
- margin-left: $govuk-gutter-half;
177
173
  vertical-align: top;
178
- // Ensure columns take up equal width (typically one-half:one-half)
179
- -webkit-box-flex: 1;
180
- -webkit-flex-grow: 1;
181
- -ms-flex-positive: 1;
182
- flex-grow: 1; // Support: Flexbox
183
- -webkit-flex-shrink: 1;
184
- -ms-flex-negative: 1;
185
- flex-shrink: 1; // Support: Flexbox
186
- @include govuk-media-query ($until: desktop) {
187
- // Make sure columns do not drop below 200px in width
188
- // Will typically result in wrapping, and end up in a single column on smaller screens.
189
- -webkit-flex-basis: 200px;
190
- -ms-flex-preferred-size: 200px;
191
- flex-basis: 200px; // Support: Flexbox
192
- }
193
- }
194
-
195
- // If there are only two sections, set the layout to be two-third:one-third on desktop
196
- @include govuk-media-query ($from: desktop) {
197
- // We match the first section with `:first-child`.
198
- // To ensure the section is one of two, we can count backwards using `:nth-last-child(2)`.
199
- .govuk-footer__section:first-child:nth-last-child(2) {
200
- -webkit-box-flex: 2;
201
- -webkit-flex-grow: 2;
202
- -ms-flex-positive: 2;
203
- flex-grow: 2; // Support: Flexbox
204
- }
205
174
  }
206
175
 
207
176
  .govuk-footer__list {
@@ -207,8 +207,13 @@
207
207
  }
208
208
 
209
209
  .govuk-header__navigation {
210
- @include govuk-responsive-margin(2, "bottom");
211
- display: block;
210
+ @include govuk-media-query ($from: desktop) {
211
+ margin-bottom: govuk-spacing(2);
212
+ }
213
+ }
214
+
215
+ .govuk-header__navigation-list {
216
+ // Reset user-agent default list styles
212
217
  margin: 0;
213
218
  padding: 0;
214
219
  list-style: none;
@@ -222,14 +227,14 @@
222
227
  }
223
228
  }
224
229
 
225
- .govuk-header__navigation {
230
+ .govuk-header__navigation-list {
226
231
  display: none;
227
232
  @include govuk-media-query ($from: desktop) {
228
233
  display: block;
229
234
  }
230
235
  }
231
236
 
232
- .govuk-header__navigation--open {
237
+ .govuk-header__navigation-list--open {
233
238
  display: block;
234
239
  }
235
240
  }
@@ -281,6 +286,7 @@
281
286
 
282
287
  .govuk-header__navigation-item:last-child {
283
288
  margin-right: 0;
289
+ border-bottom: 0;
284
290
  }
285
291
 
286
292
  @include govuk-media-query($media-type: print) {