govuk_publishing_components 45.0.0 → 45.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (20) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-schemas.js +3 -1
  3. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-search-tracker.js +17 -0
  4. data/app/assets/javascripts/govuk_publishing_components/components/search-with-autocomplete.js +50 -9
  5. data/app/controllers/govuk_publishing_components/component_guide_controller.rb +16 -6
  6. data/app/models/govuk_publishing_components/component_docs.rb +6 -6
  7. data/app/models/govuk_publishing_components/component_wrapper_helper_options.rb +1 -0
  8. data/app/views/govuk_publishing_components/component_guide/index.html.erb +29 -20
  9. data/app/views/govuk_publishing_components/components/_error_message.html.erb +6 -4
  10. data/app/views/govuk_publishing_components/components/_feedback.html.erb +7 -4
  11. data/app/views/govuk_publishing_components/components/_layout_for_public.html.erb +4 -1
  12. data/app/views/govuk_publishing_components/components/_radio.html.erb +6 -4
  13. data/app/views/govuk_publishing_components/components/_summary_card.html.erb +5 -1
  14. data/app/views/govuk_publishing_components/components/docs/error_message.yml +1 -0
  15. data/app/views/govuk_publishing_components/components/docs/feedback.yml +1 -0
  16. data/app/views/govuk_publishing_components/components/docs/layout_for_public.yml +12 -1
  17. data/app/views/govuk_publishing_components/components/docs/radio.yml +1 -0
  18. data/lib/govuk_publishing_components/presenters/component_wrapper_helper.rb +16 -0
  19. data/lib/govuk_publishing_components/version.rb +1 -1
  20. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7f69da2d6425fd2326067d51ea5a3d953cba156bcafe1df093d7a5a9b209859f
4
- data.tar.gz: cb6cc4b6d22d614ca7d87a293a7cb410745d684b27b41a2e8ad65f4cfccc1b26
3
+ metadata.gz: f938838d6305407995b5a36bad862a8fe5d802bbbef0ac614a79d85c9588b48e
4
+ data.tar.gz: 3e1b2395dade924fd5a57441818beeb2b809bfa6c260c694c1e5611c5c0eaaf1
5
5
  SHA512:
6
- metadata.gz: f5e51f0e18799dec5d4fdbfd7170f93399b395ac0b4305f7ceb1171ffbdb5b13e2b69a2f52f75cfd6b29999649122e9997c1d28fbdb5686a5705de9f954fa718
7
- data.tar.gz: 15c644be77a755d6b1fda8d6060bfb88eb52c63b341999a3561c5ef2bac3ae682addb98d85d9524856467442005eaea9a62c981174b133977cccded09ef2e62e
6
+ metadata.gz: 8dd6560730fd2aaf23ad8bad8d2fa6b16576a9d1f2d4cfaf2182cee0b53531171796d494e25b1f7c614558ffc003bbd4c1de5882203ebda1526c5d763c2e1cb0
7
+ data.tar.gz: b0d5aab888e3ac4e3de918e3685fbe092e7adb5c77e7f220b8457e9f289109fdbee67bce72502d3411b2fe00b588f4b4972ac2ff63a29bb6d3d9f759f4ade86c
@@ -31,7 +31,9 @@
31
31
  percent_scrolled: this.undefined,
32
32
  video_current_time: this.undefined,
33
33
  length: this.undefined,
34
- video_percent: this.undefined
34
+ video_percent: this.undefined,
35
+ autocomplete_input: this.undefined,
36
+ autocomplete_suggestions: this.undefined
35
37
  }
36
38
  }
37
39
  }
@@ -36,6 +36,10 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
36
36
  }
37
37
 
38
38
  trackSearch () {
39
+ // The original search input may have been removed from the DOM by the autocomplete component
40
+ // if it is used, so make sure we are tracking the correct input
41
+ this.$searchInput = this.$module.querySelector('input[type="search"]')
42
+
39
43
  if (this.skipTracking()) return
40
44
 
41
45
  const data = {
@@ -50,6 +54,19 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
50
54
  text: this.searchTerm()
51
55
  }
52
56
 
57
+ if (this.$searchInput.dataset.autocompleteTriggerInput) {
58
+ // Only set the tool_name if the autocomplete was accepted, but the other autocomplete
59
+ // attributes should be included regardless (that way we can differentiate between users
60
+ // having seen the autocomplete and not used it, and not having seen it at all)
61
+ if (this.$searchInput.dataset.autocompleteAccepted === 'true') {
62
+ data.tool_name = 'autocomplete'
63
+ }
64
+
65
+ data.length = Number(this.$searchInput.dataset.autocompleteSuggestionsCount)
66
+ data.autocomplete_input = this.$searchInput.dataset.autocompleteTriggerInput
67
+ data.autocomplete_suggestions = this.$searchInput.dataset.autocompleteSuggestions
68
+ }
69
+
53
70
  window.GOVUK.analyticsGa4.core.applySchemaAndSendData(data, 'event_data')
54
71
  }
55
72
 
@@ -15,6 +15,8 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
15
15
 
16
16
  this.sourceUrl = this.$module.getAttribute('data-source-url')
17
17
  this.sourceKey = this.$module.getAttribute('data-source-key')
18
+
19
+ this.isSubmitting = false
18
20
  }
19
21
 
20
22
  init () {
@@ -28,7 +30,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
28
30
  confirmOnBlur: false,
29
31
  showNoOptionsFound: false,
30
32
  source: this.getResults.bind(this),
31
- onConfirm: this.submitContainingForm.bind(this),
33
+ onConfirm: this.onConfirm.bind(this),
32
34
  templates: {
33
35
  suggestion: this.constructSuggestionHTMLString.bind(this)
34
36
  },
@@ -54,6 +56,19 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
54
56
  this.$autocompleteInput.setAttribute('type', 'search')
55
57
  // Remove the original input from the DOM
56
58
  this.$originalInput.parentNode.removeChild(this.$originalInput)
59
+
60
+ // The accessible-autocomplete component has an edge case where when the menu is visible, it
61
+ // prevents default on the Enter key event, even if the user hasn't put keyboard focus on a
62
+ // suggestion. This results in a scenario where the user types something, does _not_ interact
63
+ // with the autocomplete menu at all, and then hits Enter to try to submit the form - but it
64
+ // isn't submitted.
65
+ //
66
+ // This manually triggers our form submission logic when the Enter key is pressed as a
67
+ // workaround (which will do nothing if the form is already in the process of submitting
68
+ // through `onConfirm` because the user has accepted a suggestion).
69
+ this.$autocompleteInput.addEventListener('keydown', (e) => {
70
+ if (e.key === 'Enter') this.submitContainingForm()
71
+ })
57
72
  }
58
73
 
59
74
  // Callback used by accessible-autocomplete to generate the HTML for each suggestion based on
@@ -87,20 +102,46 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
87
102
  url.searchParams.set('q', query)
88
103
  fetch(url, { headers: { Accept: 'application/json' } })
89
104
  .then(response => response.json())
90
- .then((data) => { populateResults(data[this.sourceKey]) })
105
+ .then((data) => {
106
+ const results = data[this.sourceKey]
107
+
108
+ this.setTrackingAttributes(query, results)
109
+ populateResults(results)
110
+ })
91
111
  .catch(() => { populateResults([]) })
92
112
  }
93
113
 
114
+ // Set tracking attributes on the input field. These can be used by the containing form's
115
+ // analytics module to track the user's interaction with the autocomplete component.
116
+ setTrackingAttributes (query, results) {
117
+ const formattedResults = results.slice(0, 5).join('|')
118
+
119
+ this.$autocompleteInput.dataset.autocompleteTriggerInput = query
120
+ this.$autocompleteInput.dataset.autocompleteSuggestions = formattedResults
121
+ this.$autocompleteInput.dataset.autocompleteSuggestionsCount = results.length
122
+ this.$autocompleteInput.dataset.autocompleteAccepted = false
123
+ }
124
+
94
125
  // Callback used by accessible-autocomplete to submit the containing form when a suggestion is
95
126
  // confirmed by the user (e.g. by pressing Enter or clicking on it)
96
- submitContainingForm (value) {
97
- if (this.$form) {
98
- // The accessible-autocomplete component calls this callback _before_ it updates its
99
- // internal state, so the value of the input field is not yet updated when this callback is
100
- // called. We need to force the value to be updated before submitting the form, but the rest
101
- // of the state can catch up later.
102
- this.$autocompleteInput.value = value
127
+ onConfirm (value) {
128
+ // The accessible-autocomplete component calls this callback _before_ it updates its
129
+ // internal state, so the value of the input field is not yet updated when this callback is
130
+ // called. We need to force the value to be updated before submitting the form, but the rest
131
+ // of the state can catch up later.
132
+ this.$autocompleteInput.value = value
133
+
134
+ this.$autocompleteInput.dataset.autocompleteAccepted = true
135
+ this.submitContainingForm()
136
+ }
103
137
 
138
+ // Submit the containing form, if one exists and the component is not already in the process of
139
+ // submitting
140
+ submitContainingForm () {
141
+ if (this.isSubmitting) return
142
+ this.isSubmitting = true
143
+
144
+ if (this.$form) {
104
145
  if (this.$form.requestSubmit) {
105
146
  this.$form.requestSubmit()
106
147
  } else {
@@ -9,7 +9,8 @@ module GovukPublishingComponents
9
9
  @component_gem_path = Gem.loaded_specs["govuk_publishing_components"].full_gem_path
10
10
  @component_docs = component_docs.all
11
11
  @gem_component_docs = gem_component_docs.all
12
- @components_in_use_docs = components_in_use_docs.used_in_this_app
12
+ @used_components = used_components_names.get_component_docs
13
+ @unused_components = unused_components_names.get_component_docs
13
14
  @components_in_use_sass = components_in_use_sass
14
15
  @components_in_use_js = components_in_use_js
15
16
  end
@@ -47,7 +48,7 @@ module GovukPublishingComponents
47
48
  additional_files = "@import 'govuk_publishing_components/govuk_frontend_support';\n"
48
49
  additional_files << "@import 'govuk_publishing_components/component_support';\n"
49
50
 
50
- components = find_all_partials_in(components_in_use)
51
+ components = find_all_partials_in(get_used_component_names)
51
52
 
52
53
  components.map { |component|
53
54
  "@import 'govuk_publishing_components/components/#{component.gsub('_', '-')}';" if component_has_sass_file(component.gsub("_", "-"))
@@ -57,7 +58,7 @@ module GovukPublishingComponents
57
58
  def components_in_use_js
58
59
  additional_files = "//= require govuk_publishing_components/lib\n"
59
60
 
60
- components = find_all_partials_in(components_in_use)
61
+ components = find_all_partials_in(get_used_component_names)
61
62
 
62
63
  components.map { |component|
63
64
  "//= require govuk_publishing_components/components/#{component.gsub('_', '-')}" if component_has_js_file(component.gsub("_", "-"))
@@ -74,11 +75,15 @@ module GovukPublishingComponents
74
75
  @gem_component_docs ||= ComponentDocs.new(gem_components: true)
75
76
  end
76
77
 
77
- def components_in_use_docs
78
- @components_in_use_docs ||= ComponentDocs.new(gem_components: true, limit_to: components_in_use)
78
+ def used_components_names
79
+ @used_components_names ||= ComponentDocs.new(gem_components: true, limit_to: get_used_component_names)
79
80
  end
80
81
 
81
- def components_in_use
82
+ def unused_components_names
83
+ @unused_components_names ||= ComponentDocs.new(gem_components: true, limit_to: get_unused_component_names)
84
+ end
85
+
86
+ def get_used_component_names
82
87
  matches = []
83
88
 
84
89
  files = Dir["#{@application_path}/app/views/**/*.erb"]
@@ -93,6 +98,11 @@ module GovukPublishingComponents
93
98
  matches.flatten.uniq.map(&:to_s).sort
94
99
  end
95
100
 
101
+ def get_unused_component_names
102
+ all_components = ComponentDocs.new(gem_components: true).all.map(&:id)
103
+ all_components - get_used_component_names
104
+ end
105
+
96
106
  def find_all_partials_in(templates)
97
107
  components = [templates]
98
108
 
@@ -12,11 +12,11 @@ module GovukPublishingComponents
12
12
  end
13
13
 
14
14
  def all
15
- fetch_component_docs.map { |component| build(component) }.sort_by(&:name)
15
+ fetch_component_doc_files.map { |component| build(component) }.sort_by(&:name)
16
16
  end
17
17
 
18
- def used_in_this_app
19
- fetch_component_docs.map { |component| build(component) if component_in_use(component[:id]) }.compact.sort_by(&:name)
18
+ def get_component_docs
19
+ fetch_component_doc_files.map { |component| build(component) if component_in_use?(component[:id]) }.compact.sort_by(&:name)
20
20
  end
21
21
 
22
22
  private
@@ -25,13 +25,13 @@ module GovukPublishingComponents
25
25
  ComponentDoc.new(component)
26
26
  end
27
27
 
28
- def fetch_component_docs
28
+ def fetch_component_doc_files
29
29
  doc_files = Rails.root.join(@documentation_directory, "*.yml")
30
30
  Dir[doc_files].sort.map { |file| parse_documentation(file) }
31
31
  end
32
32
 
33
- def component_in_use(component)
34
- true if @limit_to.include?(component)
33
+ def component_in_use?(component)
34
+ @limit_to.include?(component)
35
35
  end
36
36
 
37
37
  def fetch_component_doc(id)
@@ -13,6 +13,7 @@ This component uses the component wrapper helper. It accepts the following optio
13
13
  - `open` - accepts an open attribute value (true or false)
14
14
  - `hidden` - accepts an empty string, 'hidden', or 'until-found'
15
15
  - `tabindex` - accepts an integer. The integer can also be passed as a string.
16
+ - `dir` - accepts 'rtl', 'ltr', or 'auto'.
16
17
  "
17
18
  end
18
19
  end
@@ -15,8 +15,20 @@
15
15
  } %>
16
16
  </form>
17
17
 
18
- <% unless ENV["MAIN_COMPONENT_GUIDE"] %>
19
- <h2 class="component-doc-h2">Gem components used by this app (<%= @components_in_use_docs.length %>)</h2>
18
+ <% if !ENV["MAIN_COMPONENT_GUIDE"] %>
19
+ <h2 class="component-doc-h2">Components in this application (<%= @component_docs.length %>)</h2>
20
+ <ul class="component-list" id="list-components-in-this-application">
21
+ <% @component_docs.each do |component_doc| %>
22
+ <li>
23
+ <%= link_to component_doc.name, component_doc_path(component_doc.id), class: "govuk-link" %>
24
+ <p>
25
+ <%= component_doc.description %>
26
+ </p>
27
+ </li>
28
+ <% end %>
29
+ </ul>
30
+
31
+ <h2 class="component-doc-h2">Gem components used by this app (<%= @used_components.length %>)</h2>
20
32
 
21
33
  <%= render "govuk_publishing_components/components/details", {
22
34
  title: "Suggested imports for this application"
@@ -41,7 +53,7 @@
41
53
  </pre>
42
54
 
43
55
  <ul class="component-list">
44
- <% @components_in_use_docs.each do |component_doc| %>
56
+ <% @used_components.each do |component_doc| %>
45
57
  <li>
46
58
  <%= link_to component_doc.name, component_doc_path(component_doc.id), class: "govuk-link" %>
47
59
  <p>
@@ -50,12 +62,10 @@
50
62
  </li>
51
63
  <% end %>
52
64
  </ul>
53
- <% end %>
54
65
 
55
- <% unless ENV["MAIN_COMPONENT_GUIDE"] %>
56
- <h2 class="component-doc-h2">Components in this application (<%= @component_docs.length %>)</h2>
57
- <ul class="component-list" id="list-components-in-this-application">
58
- <% @component_docs.each do |component_doc| %>
66
+ <h2 class="component-doc-h2">Gem components not used by this app (<%= @unused_components.length %>)</h2>
67
+ <ul class="component-list">
68
+ <% @unused_components.each do |component_doc| %>
59
69
  <li>
60
70
  <%= link_to component_doc.name, component_doc_path(component_doc.id), class: "govuk-link" %>
61
71
  <p>
@@ -65,20 +75,19 @@
65
75
  <% end %>
66
76
  </ul>
67
77
 
68
- <h2 class="component-doc-h2">All gem components (<%= @gem_component_docs.length %>)</h2>
78
+ <% else %>
79
+ <ul class="component-list" id="list-all-components-in-the-gem">
80
+ <% @gem_component_docs.each do |component_doc| %>
81
+ <li>
82
+ <%= link_to component_doc.name, component_doc_path(component_doc.id), class: "govuk-link" %>
83
+ <p>
84
+ <%= component_doc.description %>
85
+ </p>
86
+ </li>
87
+ <% end %>
88
+ </ul>
69
89
  <% end %>
70
90
 
71
- <ul class="component-list" id="list-all-components-in-the-gem">
72
- <% @gem_component_docs.each do |component_doc| %>
73
- <li>
74
- <%= link_to component_doc.name, component_doc_path(component_doc.id), class: "govuk-link" %>
75
- <p>
76
- <%= component_doc.description %>
77
- </p>
78
- </li>
79
- <% end %>
80
- </ul>
81
-
82
91
  <div class="component-markdown">
83
92
  <p class="govuk-body">If you cannot find a suitable component consider extending an existing component or <a href="https://github.com/alphagov/govuk_publishing_components/blob/main/docs/generate-a-new-component.md">creating a new one</a>.</p>
84
93
  </div>
@@ -2,9 +2,6 @@
2
2
  add_gem_component_stylesheet("error-message")
3
3
 
4
4
  id ||= "error-message-#{SecureRandom.hex(4)}"
5
- classes ||= ''
6
- css_classes = %w( gem-c-error-message govuk-error-message )
7
- css_classes << classes if classes
8
5
  items ||= []
9
6
  right_to_left ||= false
10
7
 
@@ -12,7 +9,12 @@
12
9
  errors = items.map { |item| capture { item[:text] } }
13
10
  text = raw(errors.join("<br />"))
14
11
  end
12
+
13
+ component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
14
+ component_helper.set_id(id)
15
+ component_helper.add_class("gem-c-error-message govuk-error-message")
16
+ component_helper.set_dir("rtl") if right_to_left
15
17
  %>
16
- <%= tag.p id: id, class: css_classes, dir: right_to_left ? "rtl" : nil do %>
18
+ <%= tag.p(**component_helper.all_attributes) do %>
17
19
  <span class="govuk-visually-hidden">Error:</span> <%= text %>
18
20
  <% end %>
@@ -11,12 +11,15 @@
11
11
  path_without_pii = utf_encode(request.fullpath.gsub(email_regex, '[email]'))
12
12
 
13
13
  disable_ga4 ||= false
14
- data_module = "feedback"
15
- data_module << " ga4-event-tracker" unless disable_ga4
14
+
15
+ component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
16
+ component_helper.add_class("gem-c-feedback govuk-!-display-none-print")
17
+ component_helper.add_data_attribute({ module: "feedback" })
18
+ component_helper.add_data_attribute({ module: "ga4-event-tracker" }) unless disable_ga4
16
19
  %>
17
20
 
18
- <div class="gem-c-feedback govuk-!-display-none-print" data-module="<%= data_module %>">
21
+ <%= tag.div(**component_helper.all_attributes) do %>
19
22
  <%= render "govuk_publishing_components/components/feedback/yes_no_banner", disable_ga4: %>
20
23
  <%= render "govuk_publishing_components/components/feedback/problem_form", url_without_pii: url_without_pii, disable_ga4: %>
21
24
  <%= render "govuk_publishing_components/components/feedback/survey_signup_form", path_without_pii: path_without_pii, disable_ga4: %>
22
- </div>
25
+ <% end %>
@@ -1,6 +1,7 @@
1
1
  <%
2
2
  add_gem_component_stylesheet("layout-for-public")
3
3
 
4
+ for_static ||= false
4
5
  emergency_banner ||= nil
5
6
  full_width ||= false
6
7
  blue_bar ||= local_assigns.include?(:blue_bar) ? local_assigns[:blue_bar] : !full_width
@@ -160,13 +161,15 @@
160
161
  <% end %>
161
162
  <% elsif custom_layout %>
162
163
  <%= yield %>
163
- <% else %>
164
+ <% elsif for_static %>
164
165
  <div id="wrapper" class="<%= "govuk-width-container" unless full_width %>">
165
166
  <%= yield :before_content %>
166
167
  <main class="govuk-main-wrapper" id="content">
167
168
  <%= yield %>
168
169
  </main>
169
170
  </div>
171
+ <% else %>
172
+ <%= yield %>
170
173
  <% end %>
171
174
 
172
175
  <% unless omit_feedback_form %>
@@ -37,9 +37,11 @@
37
37
  hint_id = "hint-#{SecureRandom.hex(4)}" if hint
38
38
  error_id = "error-#{SecureRandom.hex(4)}"
39
39
 
40
- form_group_css_classes = %w(govuk-form-group)
41
- form_group_css_classes << "govuk-form-group--error" if has_error
42
- form_group_css_classes << shared_helper.get_margin_bottom
40
+ component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
41
+ component_helper.add_class("govuk-form-group")
42
+ component_helper.add_class("govuk-form-group--error") if has_error
43
+ component_helper.add_class(shared_helper.get_margin_bottom)
44
+ component_helper.set_id(id)
43
45
 
44
46
  radio_classes = %w(govuk-radios)
45
47
  radio_classes << "govuk-radios--small" if small
@@ -54,7 +56,7 @@
54
56
  # check if any item is set as being conditional
55
57
  has_conditional = items.any? { |item| item.is_a?(Hash) && item[:conditional] }
56
58
  %>
57
- <%= tag.div id: id, class: form_group_css_classes do %>
59
+ <%= tag.div(**component_helper.all_attributes) do %>
58
60
  <%= tag.fieldset class: "govuk-fieldset", "aria-describedby": aria do %>
59
61
  <% if heading.present? %>
60
62
  <%= tag.legend class: legend_classes do %>
@@ -28,7 +28,11 @@
28
28
  <%= tag.div class: "govuk-summary-card__content" do %>
29
29
  <%= tag.dl class: "govuk-summary-list" do %>
30
30
  <% rows.each do |row| %>
31
- <%= tag.div class: "govuk-summary-list__row", data: row[:data] do %>
31
+ <%
32
+ row_classes = "govuk-summary-list__row"
33
+ row_classes << " govuk-summary-list__row--no-actions" if row[:actions].blank?
34
+ %>
35
+ <%= tag.div class: row_classes, data: row[:data] do %>
32
36
  <%= tag.dt class: "govuk-summary-list__key" do %>
33
37
  <%= row[:key] %>
34
38
  <% end %>
@@ -10,6 +10,7 @@ accessibility_criteria: |
10
10
  - be associated with an input. The `error_message_id` must match the `aria-describedby` property on the input your label is associated with. Note that if `id` is not passed to the component an id will be generated automatically.
11
11
 
12
12
  If error message is within a label it will be announced in its entirety by screen readers. By associating error messages with inputs using `aria-describedby`, then screen readers will read the label, describe the type of input (eg radio) and then read additional text. It means users of screen readers can scan and skip options as easy as people making choices with sight.
13
+ uses_component_wrapper_helper: true
13
14
  examples:
14
15
  default:
15
16
  data:
@@ -4,6 +4,7 @@ body: |
4
4
  This component is designed to sit at the bottom of pages on GOV.UK to allow users to submit feedback on that page.
5
5
 
6
6
  This component uses JavaScript for expanding and collapsing and also for submitting form responses. This code is not compatible with Internet Explorer, so IE11 and down do not use JavaScript to submit the forms, instead falling back to a normal form submission.
7
+ uses_component_wrapper_helper: true
7
8
  accessibility_criteria: |
8
9
  The form must:
9
10
 
@@ -17,9 +17,19 @@ examples:
17
17
  title: 'Example layout'
18
18
  block: |
19
19
  <h1>Page content goes here</h1>
20
+ with_static_wrapper:
21
+ description: |
22
+ By default, the layout does not include the `div#wrapper` element, nor the `main` element within that.
23
+ This behaviour is peculiar to the one app that currently uses this layout - static. Static now sets the `for_static: true` flag,
24
+ which causes the wrapper to be included. Other apps in the future will not set that flag, but provide their own wrapper and main elements.
25
+ data:
26
+ for_static: true
27
+ block: |
28
+ <h1>Page content goes here</h1>
20
29
  full_width:
21
- description: By default, the layout applies the `govuk-width-container` class to the main element. We can remove this class by setting `full_width` to `true`
30
+ description: By default, the layout applies the `govuk-width-container` class to the main element. We can remove this class by setting `full_width` to `true`. Note this also requires the for_static flag, since that is needed for the main element.
22
31
  data:
32
+ for_static: true
23
33
  full_width: true
24
34
  block: |
25
35
  <h1>Page content goes here</h1>
@@ -30,6 +40,7 @@ examples:
30
40
  blue_bar_background:
31
41
  description: For use when a page has a heading component with a background colour.
32
42
  data:
43
+ for_static: true
33
44
  full_width: true
34
45
  blue_bar: true
35
46
  blue_bar_background_colour: "no"
@@ -4,6 +4,7 @@ body: |
4
4
  You can also use 'or' as an item to break up radios.
5
5
 
6
6
  If JavaScript is disabled a conditionally revealed content expands fully. All of the functionality (including aria attributes) are added using JavaScript.
7
+ uses_component_wrapper_helper: true
7
8
  accessibility_criteria: |
8
9
  Radio buttons should
9
10
 
@@ -13,6 +13,7 @@ module GovukPublishingComponents
13
13
  check_open_is_valid(@options[:open]) if @options.include?(:open)
14
14
  check_hidden_is_valid(@options[:hidden]) if @options.include?(:hidden)
15
15
  check_tabindex_is_valid(@options[:tabindex]) if @options.include?(:tabindex)
16
+ check_dir_is_valid(@options[:dir]) if @options.include?(:dir)
16
17
  end
17
18
 
18
19
  def all_attributes
@@ -27,6 +28,7 @@ module GovukPublishingComponents
27
28
  attributes[:open] = @options[:open] unless @options[:open].blank?
28
29
  attributes[:hidden] = @options[:hidden] unless @options[:hidden].nil?
29
30
  attributes[:tabindex] = @options[:tabindex] unless @options[:tabindex].blank?
31
+ attributes[:dir] = @options[:dir] unless @options[:dir].blank?
30
32
 
31
33
  attributes
32
34
  end
@@ -76,6 +78,11 @@ module GovukPublishingComponents
76
78
  @options[:tabindex] = tabindex_attribute
77
79
  end
78
80
 
81
+ def set_dir(dir_attribute)
82
+ check_dir_is_valid(dir_attribute)
83
+ @options[:dir] = dir_attribute
84
+ end
85
+
79
86
  private
80
87
 
81
88
  def check_id_is_valid(id)
@@ -163,6 +170,15 @@ module GovukPublishingComponents
163
170
  end
164
171
  end
165
172
 
173
+ def check_dir_is_valid(dir_attribute)
174
+ return if dir_attribute.nil?
175
+
176
+ options = %w[ltr rtl auto]
177
+ unless options.include? dir_attribute
178
+ raise(ArgumentError, "dir attribute (#{dir_attribute}) is not recognised")
179
+ end
180
+ end
181
+
166
182
  def extend_string(option, string)
167
183
  ((@options[option] ||= "") << " #{string}").strip!
168
184
  end
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "45.0.0".freeze
2
+ VERSION = "45.2.0".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: govuk_publishing_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 45.0.0
4
+ version: 45.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GOV.UK Dev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-06 00:00:00.000000000 Z
11
+ date: 2024-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chartkick