govuk_publishing_components 24.3.1 → 24.6.1

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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/components/accordion.js +7 -5
  3. data/app/assets/javascripts/govuk_publishing_components/components/details.js +1 -1
  4. data/app/assets/javascripts/govuk_publishing_components/components/reorderable-list.js +108 -0
  5. data/app/assets/javascripts/govuk_publishing_components/components/show-password.js +7 -2
  6. data/app/assets/javascripts/govuk_publishing_components/lib/header-navigation.js +6 -2
  7. data/app/assets/stylesheets/govuk_publishing_components/_all_components.scss +1 -0
  8. data/app/assets/stylesheets/govuk_publishing_components/_all_components_print.scss +1 -1
  9. data/app/assets/stylesheets/govuk_publishing_components/components/_breadcrumbs.scss +11 -0
  10. data/app/assets/stylesheets/govuk_publishing_components/components/_reorderable-list.scss +117 -0
  11. data/app/assets/stylesheets/govuk_publishing_components/components/_summary-list.scss +12 -0
  12. data/app/views/govuk_publishing_components/components/_breadcrumbs.html.erb +8 -5
  13. data/app/views/govuk_publishing_components/components/_list.html.erb +5 -5
  14. data/app/views/govuk_publishing_components/components/_radio.html.erb +2 -1
  15. data/app/views/govuk_publishing_components/components/_reorderable_list.html.erb +45 -0
  16. data/app/views/govuk_publishing_components/components/_search.html.erb +27 -16
  17. data/app/views/govuk_publishing_components/components/_show_password.html.erb +6 -4
  18. data/app/views/govuk_publishing_components/components/_summary_list.html.erb +73 -31
  19. data/app/views/govuk_publishing_components/components/docs/breadcrumbs.yml +22 -0
  20. data/app/views/govuk_publishing_components/components/docs/radio.yml +14 -1
  21. data/app/views/govuk_publishing_components/components/docs/reorderable_list.yml +85 -0
  22. data/app/views/govuk_publishing_components/components/docs/search.yml +10 -0
  23. data/app/views/govuk_publishing_components/components/docs/summary_list.yml +50 -19
  24. data/app/views/govuk_publishing_components/components/layout_header/_search.html.erb +17 -3
  25. data/config/locales/en.yml +25 -15
  26. data/lib/govuk_publishing_components/version.rb +1 -1
  27. data/node_modules/sortablejs/LICENSE +21 -0
  28. data/node_modules/sortablejs/README.md +815 -0
  29. data/node_modules/sortablejs/Sortable.js +3721 -0
  30. data/node_modules/sortablejs/Sortable.min.js +2 -0
  31. data/node_modules/sortablejs/modular/sortable.complete.esm.js +3713 -0
  32. data/node_modules/sortablejs/modular/sortable.core.esm.js +3710 -0
  33. data/node_modules/sortablejs/modular/sortable.esm.js +3711 -0
  34. data/node_modules/sortablejs/package.json +56 -0
  35. metadata +14 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbfbb444f86b61f46e110ab8615ca02b163357d6bf3125c4f4459bed3da8b92d
4
- data.tar.gz: 012a4752e5fd69378516db6348f18b14902714dc56e209951879f490af850f77
3
+ metadata.gz: b8b508d510a7aa8f9311afcb0cbb99c28c02b8128e231fbddea0ceac450bda59
4
+ data.tar.gz: 2fc60e40d72fdb1fd6dfb635782a982e5105c4df41d8a40e71ff2985b669eaed
5
5
  SHA512:
6
- metadata.gz: 94f375971a2803179d77d070ee86113ea6e6a17d5e547d94c7229b7fcd643b2e8636eccb1f03369e26bb074517bdf411312826a721701efd55363fab244033a2
7
- data.tar.gz: 62c13a38b68951a6492044e29b4a7989ea2ea62e185b58c307707bdbbe9a013e4db03dc7c52b7d378f04474be5e8505751e5395d4c58f5d6cc8e8ded2a9ede83
6
+ metadata.gz: 2a43864b134f08d16145c1f39ade8bb21de88cfbe9e2f9bb92af0780e2cce92da0381495a61a9d95e40f80d66a6a739ba75ad00b18c975df2f2ccd8232749d2c
7
+ data.tar.gz: a379f9f22980a8dbddd8e0af9752055ad8f93fd45a144a1a339d153c5670d26e6bbbda904acd13b91c56e0e797a8e9ed5b82cd190dd9926810d2c41d12ba4691
@@ -293,8 +293,10 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
293
293
 
294
294
  // Navigate to and open accordions with anchored content on page load if a hash is present
295
295
  GemAccordion.prototype.openByAnchorOnLoad = function () {
296
- if (window.location.hash && this.$module.querySelector(window.location.hash)) {
297
- this.openForAnchor(window.location.hash)
296
+ var splitHash = window.location.hash.split('#')[1]
297
+
298
+ if (window.location.hash && document.getElementById(splitHash)) {
299
+ this.openForAnchor(splitHash)
298
300
  }
299
301
  }
300
302
 
@@ -305,20 +307,20 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
305
307
 
306
308
  links.forEach(function (link) {
307
309
  if (link.pathname === window.location.pathname) {
308
- link.addEventListener('click', this.openForAnchor.bind(this, link.hash))
310
+ link.addEventListener('click', this.openForAnchor.bind(this, link.hash.split('#')[1]))
309
311
  }
310
312
  }.bind(this))
311
313
  }
312
314
 
313
315
  // Find the parent accordion section for the given id and open it
314
316
  GemAccordion.prototype.openForAnchor = function (hash) {
315
- var target = document.querySelector(hash)
317
+ var target = document.getElementById(hash)
316
318
  var section = this.getContainingSection(target)
317
319
 
318
320
  this.setExpanded(true, section)
319
321
  }
320
322
 
321
- // Loop through the given ids ancestors until the parent section class is found
323
+ // Loop through the given id's ancestors until the parent section class is found
322
324
  GemAccordion.prototype.getContainingSection = function (target) {
323
325
  while (!target.classList.contains(this.sectionClass)) {
324
326
  target = target.parentElement
@@ -13,7 +13,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
13
13
 
14
14
  // If a custom label has been provided, we can simply call the tracking module
15
15
  if (customTrackLabel) {
16
- var trackDetails = new window.GOVUK.Modules.TrackClick()
16
+ var trackDetails = new window.GOVUK.Modules.GemTrackClick()
17
17
  trackDetails.start($module)
18
18
  } else {
19
19
  // If no custom label is set, we use the open/close status as the label
@@ -0,0 +1,108 @@
1
+ //= require sortablejs/Sortable.js
2
+ window.GOVUK = window.GOVUK || {}
3
+ window.GOVUK.Modules = window.GOVUK.Modules || {};
4
+
5
+ (function (Modules) {
6
+ function ReorderableList () { }
7
+
8
+ ReorderableList.prototype.start = function ($module) {
9
+ this.$module = $module[0]
10
+ this.$upButtons = this.$module.querySelectorAll('.js-reorderable-list-up')
11
+ this.$downButtons = this.$module.querySelectorAll('.js-reorderable-list-down')
12
+
13
+ this.sortable = window.Sortable.create(this.$module, { // eslint-disable-line new-cap
14
+ chosenClass: 'gem-c-reorderable-list__item--chosen',
15
+ dragClass: 'gem-c-reorderable-list__item--drag',
16
+ onSort: function () {
17
+ this.updateOrderIndexes()
18
+ this.triggerEvent(this.$module, 'reorder-drag')
19
+ }.bind(this)
20
+ })
21
+
22
+ if (typeof window.matchMedia === 'function') {
23
+ this.setupResponsiveChecks()
24
+ } else {
25
+ this.sortable.option('disabled', true)
26
+ }
27
+
28
+ var boundOnClickUpButton = this.onClickUpButton.bind(this)
29
+ this.$upButtons.forEach(function (button) {
30
+ button.addEventListener('click', boundOnClickUpButton)
31
+ })
32
+
33
+ var boundOnClickDownButton = this.onClickDownButton.bind(this)
34
+ this.$downButtons.forEach(function (button) {
35
+ button.addEventListener('click', boundOnClickDownButton)
36
+ })
37
+ }
38
+
39
+ ReorderableList.prototype.setupResponsiveChecks = function () {
40
+ var tabletBreakpoint = '40.0625em' // ~640px
41
+ this.mediaQueryList = window.matchMedia('(min-width: ' + tabletBreakpoint + ')')
42
+ this.mediaQueryList.addListener(this.checkMode.bind(this))
43
+ this.checkMode()
44
+ }
45
+
46
+ ReorderableList.prototype.checkMode = function () {
47
+ this.sortable.option('disabled', !this.mediaQueryList.matches)
48
+ }
49
+
50
+ ReorderableList.prototype.onClickUpButton = function (e) {
51
+ var item = e.target.closest('.gem-c-reorderable-list__item')
52
+ var previousItem = item.previousElementSibling
53
+ if (item && previousItem) {
54
+ item.parentNode.insertBefore(item, previousItem)
55
+ this.updateOrderIndexes()
56
+ }
57
+ // if triggered by keyboard preserve focus on button
58
+ if (e.detail === 0) {
59
+ if (item !== item.parentNode.firstElementChild) {
60
+ e.target.focus()
61
+ } else {
62
+ e.target.nextElementSibling.focus()
63
+ }
64
+ }
65
+ this.triggerEvent(e.target, 'reorder-move-up')
66
+ }
67
+
68
+ ReorderableList.prototype.onClickDownButton = function (e) {
69
+ var item = e.target.closest('.gem-c-reorderable-list__item')
70
+ var nextItem = item.nextElementSibling
71
+ if (item && nextItem) {
72
+ item.parentNode.insertBefore(item, nextItem.nextElementSibling)
73
+ this.updateOrderIndexes()
74
+ }
75
+ // if triggered by keyboard preserve focus on button
76
+ if (e.detail === 0) {
77
+ if (item !== item.parentNode.lastElementChild) {
78
+ e.target.focus()
79
+ } else {
80
+ e.target.previousElementSibling.focus()
81
+ }
82
+ }
83
+ this.triggerEvent(e.target, 'reorder-move-down')
84
+ }
85
+
86
+ ReorderableList.prototype.updateOrderIndexes = function () {
87
+ var $orderInputs = this.$module.querySelectorAll('.gem-c-reorderable-list__actions input')
88
+ $orderInputs.forEach(function (input, index) {
89
+ input.setAttribute('value', index + 1)
90
+ })
91
+ }
92
+
93
+ ReorderableList.prototype.triggerEvent = function (element, eventName) {
94
+ var params = { bubbles: true, cancelable: true }
95
+ var event
96
+
97
+ if (typeof window.CustomEvent === 'function') {
98
+ event = new window.CustomEvent(eventName, params)
99
+ } else {
100
+ event = document.createEvent('CustomEvent')
101
+ event.initCustomEvent(eventName, params.bubbles, params.cancelable)
102
+ }
103
+
104
+ element.dispatchEvent(event)
105
+ }
106
+
107
+ Modules.ReorderableList = ReorderableList
108
+ })(window.GOVUK.Modules)
@@ -11,8 +11,10 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
11
11
  this.$module.revertToPasswordOnFormSubmit = this.revertToPasswordOnFormSubmit.bind(this)
12
12
  this.input.classList.add('gem-c-input--with-password')
13
13
 
14
- this.showPasswordText = this.$module.getAttribute('data-show')
15
- this.hidePasswordText = this.$module.getAttribute('data-hide')
14
+ this.showPasswordText = this.$module.getAttribute('data-show-text')
15
+ this.hidePasswordText = this.$module.getAttribute('data-hide-text')
16
+ this.showPasswordFullText = this.$module.getAttribute('data-show-full-text')
17
+ this.hidePasswordFullText = this.$module.getAttribute('data-hide-full-text')
16
18
  this.shownPassword = this.$module.getAttribute('data-announce-show')
17
19
  this.hiddenPassword = this.$module.getAttribute('data-announce-hide')
18
20
 
@@ -27,6 +29,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
27
29
  this.showHide.className = 'gem-c-show-password__toggle'
28
30
  this.showHide.setAttribute('aria-controls', this.input.getAttribute('id'))
29
31
  this.showHide.setAttribute('type', 'button')
32
+ this.showHide.setAttribute('aria-label', this.showPasswordFullText)
30
33
  this.showHide.innerHTML = this.showPasswordText
31
34
  this.wrapper.insertBefore(this.showHide, this.input.nextSibling)
32
35
 
@@ -50,12 +53,14 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
50
53
  ShowPassword.prototype.togglePassword = function (event) {
51
54
  event.preventDefault()
52
55
  this.showHide.innerHTML = this.showHide.innerHTML === this.showPasswordText ? this.hidePasswordText : this.showPasswordText
56
+ this.showHide.setAttribute('aria-label', this.showHide.getAttribute('aria-label') === this.showPasswordFullText ? this.hidePasswordFullText : this.showPasswordFullText)
53
57
  this.statusText.innerHTML = this.statusText.innerHTML === this.shownPassword ? this.hiddenPassword : this.shownPassword
54
58
  this.input.setAttribute('type', this.input.getAttribute('type') === 'text' ? 'password' : 'text')
55
59
  }
56
60
 
57
61
  ShowPassword.prototype.revertToPasswordOnFormSubmit = function (event) {
58
62
  this.showHide.innerHTML = this.showPasswordText
63
+ this.showHide.setAttribute('aria-label', this.showPasswordFullText)
59
64
  this.statusText.innerHTML = this.hiddenPassword
60
65
  this.input.setAttribute('type', 'password')
61
66
  }
@@ -1,3 +1,5 @@
1
+ /* eslint-disable no-var */
2
+
1
3
  // used by the header navigation from govuk_template
2
4
 
3
5
  (function () {
@@ -14,6 +16,8 @@
14
16
  var targetClass = target.getAttribute('class') || ''
15
17
  var sourceClass = this.getAttribute('class') || ''
16
18
  var isSearchToggle = sourceClass.match('search-toggle')
19
+ var showText = this.getAttribute('data-show-text') || 'Show search'
20
+ var hideText = this.getAttribute('data-hide-text') || 'Hide search'
17
21
 
18
22
  if (targetClass.indexOf('js-visible') !== -1) {
19
23
  target.setAttribute('class', targetClass.replace(/(^|\s)js-visible(\s|$)/, ''))
@@ -23,12 +27,12 @@
23
27
  if (sourceClass.indexOf('js-visible') !== -1) {
24
28
  this.setAttribute('class', sourceClass.replace(/(^|\s)js-visible(\s|$)/, ''))
25
29
  if (isSearchToggle) {
26
- this.innerText = 'Show search'
30
+ this.innerText = showText
27
31
  }
28
32
  } else {
29
33
  this.setAttribute('class', sourceClass + ' js-visible')
30
34
  if (isSearchToggle) {
31
- this.innerText = 'Hide search'
35
+ this.innerText = hideText
32
36
  }
33
37
  }
34
38
  this.setAttribute('aria-expanded', this.getAttribute('aria-expanded') !== 'true')
@@ -56,6 +56,7 @@
56
56
  @import "components/print-link";
57
57
  @import "components/radio";
58
58
  @import "components/related-navigation";
59
+ @import "components/reorderable-list";
59
60
  @import "components/search";
60
61
  @import "components/select";
61
62
  @import "components/share-links";
@@ -1,7 +1,7 @@
1
1
  // This is the file that the application needs to include in order to use
2
2
  // the components.
3
3
 
4
- @import "components/helpers/govuk-frontend-settings";
4
+ @import "govuk_frontend_support";
5
5
 
6
6
  @import "components/print/accordion";
7
7
  @import "components/print/attachment";
@@ -21,6 +21,17 @@
21
21
  border-color: govuk-colour("white");
22
22
  }
23
23
 
24
+ .gem-c-breadcrumbs--border-bottom {
25
+ border-bottom: 1px solid $govuk-border-colour;
26
+ padding-bottom: govuk-spacing(1);
27
+
28
+ &.govuk-breadcrumbs--collapse-on-mobile {
29
+ @include govuk-media-query($until: tablet) {
30
+ padding-bottom: 0;
31
+ }
32
+ }
33
+ }
34
+
24
35
  .govuk-breadcrumbs--collapse-on-mobile {
25
36
  @include govuk-media-query($until: tablet) {
26
37
  .govuk-breadcrumbs__list-item {
@@ -0,0 +1,117 @@
1
+ .gem-c-reorderable-list {
2
+ @include govuk-font(19, bold);
3
+
4
+ list-style-type: none;
5
+ margin-bottom: govuk-spacing(6);
6
+ margin-top: 0;
7
+ padding-left: 0;
8
+ position: relative;
9
+
10
+ .govuk-form-group {
11
+ margin-bottom: 0;
12
+ }
13
+ }
14
+
15
+ .gem-c-reorderable-list__item {
16
+ margin-bottom: govuk-spacing(3);
17
+ border: 1px solid $govuk-border-colour;
18
+ padding: govuk-spacing(3);
19
+ }
20
+
21
+ .gem-c-reorderable-list__item--chosen {
22
+ background-color: govuk-colour('light-grey');
23
+ outline: 2px dotted $govuk-border-colour;
24
+ }
25
+
26
+ .gem-c-reorderable-list__item--drag {
27
+ background-color: govuk-colour('white');
28
+ list-style-type: none;
29
+
30
+ .gem-c-reorderable-list__actions {
31
+ visibility: hidden;
32
+ }
33
+ }
34
+
35
+ .gem-c-reorderable-list__wrapper {
36
+ display: block;
37
+
38
+ @include govuk-media-query($from: desktop) {
39
+ display: inline-flex;
40
+ width: 100%;
41
+ }
42
+ }
43
+
44
+ .gem-c-reorderable-list__content {
45
+ margin-bottom: govuk-spacing(2);
46
+ @include govuk-media-query($from: desktop) {
47
+ margin-bottom: 0;
48
+ flex: 0 1 auto;
49
+ min-width: 65%;
50
+ }
51
+ }
52
+
53
+ .gem-c-reorderable-list__title {
54
+ margin: 0;
55
+ }
56
+
57
+ .gem-c-reorderable-list__description {
58
+ @include govuk-font(16, regular);
59
+ margin: 0;
60
+ }
61
+
62
+ .gem-c-reorderable-list__actions {
63
+ display: block;
64
+
65
+ @include govuk-media-query($from: desktop) {
66
+ flex: 1 0 auto;
67
+ text-align: right;
68
+ }
69
+
70
+ .gem-c-button {
71
+ display: none;
72
+ }
73
+ }
74
+
75
+ .js-enabled {
76
+ .gem-c-reorderable-list__item {
77
+ @include govuk-media-query($from: desktop) {
78
+ cursor: move;
79
+ }
80
+ }
81
+
82
+ .gem-c-reorderable-list__actions .govuk-form-group {
83
+ display: none;
84
+ }
85
+
86
+ .gem-c-reorderable-list__actions .gem-c-button {
87
+ display: inline-block;
88
+ margin-left: govuk-spacing(3);
89
+ width: 80px;
90
+ }
91
+
92
+ .gem-c-reorderable-list__actions .gem-c-button:first-of-type {
93
+ margin-left: 0;
94
+
95
+ @include govuk-media-query($from: desktop) {
96
+ margin-left: govuk-spacing(3);
97
+ }
98
+ }
99
+
100
+ .gem-c-reorderable-list__item:first-child .gem-c-button:first-of-type,
101
+ .gem-c-reorderable-list__item:last-child .gem-c-button:last-of-type {
102
+ display: none;
103
+
104
+ @include govuk-media-query($from: desktop) {
105
+ display: inline-block;
106
+ visibility: hidden;
107
+ }
108
+ }
109
+
110
+ .gem-c-reorderable-list__item:first-child .gem-c-button:last-of-type {
111
+ margin-left: 0;
112
+
113
+ @include govuk-media-query($from: desktop) {
114
+ margin-left: govuk-spacing(3);
115
+ }
116
+ }
117
+ }
@@ -38,3 +38,15 @@
38
38
  .gem-c-summary__block {
39
39
  @include govuk-responsive-margin(6, "bottom");
40
40
  }
41
+
42
+ .gem-c-summary-list--wide-title {
43
+ @include govuk-media-query($from: 'tablet') {
44
+ .govuk-summary-list__key {
45
+ width: 60%;
46
+ }
47
+
48
+ .govuk-summary-list__value {
49
+ width: 20%;
50
+ }
51
+ }
52
+ }
@@ -1,19 +1,22 @@
1
1
  <%
2
+ border ||= false
2
3
  breadcrumbs ||= []
3
- inverse ||= false
4
4
  collapse_on_mobile ||= false
5
+ inverse ||= false
6
+
5
7
  breadcrumb_presenter = GovukPublishingComponents::Presenters::Breadcrumbs.new(breadcrumbs)
6
8
 
7
- classes = "gem-c-breadcrumbs govuk-breadcrumbs"
8
- classes << " govuk-breadcrumbs--collapse-on-mobile" if collapse_on_mobile
9
- classes << " gem-c-breadcrumbs--inverse" if inverse
9
+ classes = %w[gem-c-breadcrumbs govuk-breadcrumbs]
10
+ classes << "govuk-breadcrumbs--collapse-on-mobile" if collapse_on_mobile
11
+ classes << "gem-c-breadcrumbs--inverse" if inverse
12
+ classes << "gem-c-breadcrumbs--border-bottom" if border == "bottom"
10
13
  %>
11
14
 
12
15
  <script type="application/ld+json">
13
16
  <%= raw JSON.pretty_generate(breadcrumb_presenter.structured_data) %>
14
17
  </script>
15
18
 
16
- <div class="<%= classes %>" data-module="gem-track-click">
19
+ <div class="<%= classes.join(" ") %>" data-module="gem-track-click">
17
20
  <ol class="govuk-breadcrumbs__list">
18
21
  <% breadcrumbs.each_with_index do |crumb, index| %>
19
22
  <% breadcrumb = GovukPublishingComponents::Presenters::Breadcrumb.new(crumb, index) %>
@@ -1,12 +1,12 @@
1
1
  <%
2
- id ||= nil
2
+ aria_label ||= nil
3
3
  extra_spacing ||= nil
4
+ id ||= nil
5
+ items ||= []
4
6
  list_type ||= "unordered"
5
7
  visible_counters ||= nil
6
- items ||= []
7
- aria_label ||= nil
8
8
 
9
- classes = %w(gem-c-list govuk-list)
9
+ classes = %w[gem-c-list govuk-list]
10
10
  classes << "govuk-list--bullet" if visible_counters && list_type === "unordered"
11
11
  classes << "govuk-list--number" if visible_counters && list_type === "number"
12
12
  classes << "govuk-list--spaced" if extra_spacing
@@ -20,7 +20,7 @@
20
20
  <% if items.any? %>
21
21
  <%= content_tag list_tag, class: classes, id: id, "aria-label": aria_label do %>
22
22
  <% items.each do |item| %>
23
- <li><%= sanitize(item) %></li>
23
+ <li><%= raw(item) %></li>
24
24
  <% end %>
25
25
  <% end %>
26
26
  <% end %>