govuk_publishing_components 35.1.1 → 35.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,6 @@
2
2
  @import "mixins/prefixed-transform";
3
3
  @import "mixins/grid-helper";
4
4
 
5
- $icon-size: 20px;
6
5
  $chevron-indent-spacing: 7px;
7
6
  $black-bar-height: 50px;
8
7
  $search-width-or-height: $black-bar-height;
@@ -343,9 +342,9 @@ $after-button-padding-left: govuk-spacing(4);
343
342
 
344
343
  .gem-c-layout-super-navigation-header__search-item-link-icon,
345
344
  .gem-c-layout-super-navigation-header__search-toggle-button-link-icon {
346
- height: $icon-size;
345
+ height: 20px;
347
346
  pointer-events: none;
348
- width: $icon-size;
347
+ width: 21px;
349
348
  }
350
349
 
351
350
  // Search and popular content dropdown.
@@ -2,7 +2,7 @@ module GovukPublishingComponents
2
2
  class ComponentGuideController < GovukPublishingComponents::ApplicationController
3
3
  append_view_path File.join(Rails.root, "app", "views", GovukPublishingComponents::Config.component_directory_name)
4
4
 
5
- MATCH_COMPONENTS = /(?<=govuk_publishing_components\/components\/)[\/a-zA-Z_-]+(?=['"])/.freeze
5
+ MATCH_COMPONENTS = /(?<=govuk_publishing_components\/components\/)[\/a-zA-Z_-]+(?=['"])/
6
6
 
7
7
  def index
8
8
  @application_path = Rails.root
@@ -18,7 +18,9 @@ module GovukPublishingComponents
18
18
 
19
19
  find_components = /(?<=govuk_publishing_components\/components\/)[a-zA-Z_-]+(?=['"])/
20
20
 
21
- @find_all_stylesheets = /@import ["']{1}govuk_publishing_components\/all_components/
21
+ @find_all_stylesheets = /@import ["']{1}govuk_publishing_components\/all_components/ # if using the all stylesheets option
22
+ @find_individual_asset_model = /render_component_stylesheets/ # if using per page component asset loading
23
+ @uses_individual_asset_model = false
22
24
  find_stylesheets = /(?<=@import ["']{1}govuk_publishing_components\/components\/)(?!print\/)+[a-zA-Z_-]+(?=['"])/
23
25
 
24
26
  @find_all_javascripts = /\/\/ *= require govuk_publishing_components\/all_components/
@@ -63,6 +65,7 @@ module GovukPublishingComponents
63
65
  jquery_references: @jquery_references.flatten.uniq.sort,
64
66
  component_locations: @component_locations,
65
67
  helper_references: @helper_references,
68
+ uses_individual_asset_model: @uses_individual_asset_model,
66
69
  }
67
70
  end
68
71
 
@@ -125,6 +128,7 @@ module GovukPublishingComponents
125
128
  return %w[all] if src.match(@find_all_stylesheets) && type == "stylesheet"
126
129
  return %w[all] if src.match(@find_all_javascripts) && type == "javascript"
127
130
 
131
+ @uses_individual_asset_model = true if src.match(@find_individual_asset_model) && type == "template"
128
132
  matches = src.scan(find)
129
133
  return [] unless matches.any?
130
134
 
@@ -54,15 +54,13 @@ module GovukPublishingComponents
54
54
 
55
55
  results.each do |result|
56
56
  if result[:application_found]
57
+ @current_uses_individual_asset_model = result[:uses_individual_asset_model]
57
58
  application_uses_static = @applications_using_static.include?(result[:name])
58
59
  templates = result[:components_found].find { |c| c[:location] == "template" }
59
60
  stylesheets = result[:components_found].find { |c| c[:location] == "stylesheet" }
60
61
  javascripts = result[:components_found].find { |c| c[:location] == "javascript" }
61
62
  ruby = result[:components_found].find { |c| c[:location] == "ruby" }
62
63
 
63
- @all_stylesheets = true if stylesheets[:components].include?("all")
64
- @all_javascripts = true if javascripts[:components].include?("all")
65
-
66
64
  templates[:components] = include_any_components_within_components(templates[:components])
67
65
 
68
66
  warnings = []
@@ -103,6 +101,7 @@ module GovukPublishingComponents
103
101
  jquery_references: result[:jquery_references],
104
102
  component_locations: result[:component_locations],
105
103
  helper_references: result[:helper_references],
104
+ uses_individual_asset_model: result[:uses_individual_asset_model],
106
105
  }
107
106
  else
108
107
  data << {
@@ -161,7 +160,8 @@ module GovukPublishingComponents
161
160
 
162
161
  check_static = @static_data && second_location != "code"
163
162
  asset_in_static = asset_already_in_static(second_location, component) if check_static
164
- raise_warning = asset_in_gem && !asset_in_static
163
+ suppress_warning = @current_uses_individual_asset_model && second_location == "stylesheet"
164
+ raise_warning = asset_in_gem && !asset_in_static && !suppress_warning
165
165
 
166
166
  # this raises a warning if the asset exists and isn't included either in the application or static
167
167
  warnings << create_warning(component, "Included in #{first_location} but not #{second_location}") if raise_warning
@@ -37,8 +37,24 @@
37
37
  <% github_link = 'https://github.com/alphagov/' + application[:name] + '/blob/main/' %>
38
38
 
39
39
  <% if @other_applications %>
40
+ <% if application[:uses_individual_asset_model] %>
41
+ <div class="govuk-warning-text">
42
+ <span class="govuk-warning-text__icon" aria-hidden="true">!</span>
43
+ <strong class="govuk-warning-text__text">
44
+ <span class="govuk-warning-text__assistive">Warning</span>
45
+ This application uses <a class="govuk-link" href="https://github.com/alphagov/govuk_publishing_components/blob/main/docs/set-up-individual-component-css-loading.md">per page asset loading</a> for components. Warnings about missing stylesheets have been suppressed.
46
+ </strong>
47
+ </div>
48
+ <% end %>
49
+
40
50
  <% if application[:uses_static] %>
41
- <p class="govuk-body">This application uses <a href="https://github.com/alphagov/static" class="govuk-link">static</a>, which can contain assets for components used in more than one application. Warnings for missing component assets in this application that are already included in static have been suppressed.</p>
51
+ <div class="govuk-warning-text">
52
+ <span class="govuk-warning-text__icon" aria-hidden="true">!</span>
53
+ <strong class="govuk-warning-text__text">
54
+ <span class="govuk-warning-text__assistive">Warning</span>
55
+ This application uses <a href="https://github.com/alphagov/static" class="govuk-link">static</a>, which can contain assets for components used in more than one application. Warnings for missing component assets in this application that are already included in static have been suppressed.
56
+ </strong>
57
+ </div>
42
58
  <% end %>
43
59
 
44
60
  <% application[:warnings].each do |warning| %>
@@ -67,6 +83,8 @@
67
83
  <dd class="govuk-summary-list__value">
68
84
  <% if item[:value].length > 0 %>
69
85
  <%= item[:value].join(", ") %>
86
+ <% elsif application[:uses_individual_asset_model] && item[:name] == "In stylesheets" %>
87
+ Uses per page component asset loading
70
88
  <% else %>
71
89
  None
72
90
  <% end %>
@@ -77,13 +95,13 @@
77
95
 
78
96
  <% if application[:gem_style_references].any? %>
79
97
  <%= render "govuk_publishing_components/components/heading", {
80
- text: "Component references",
98
+ text: "Component references (#{application[:gem_style_references].length})",
81
99
  font_size: "m",
82
100
  margin_bottom: 4,
83
101
  heading_level: 3,
84
102
  } %>
85
103
 
86
- <p class="govuk-body">This shows instances of `gem-c-` classes found in the application. If a reference is found in a stylesheet or in code a warning is created, as this could be a style override or hard coded component markup.</p>
104
+ <p class="govuk-body">This shows instances of `gem-c-` classes found in the application. This could be a style override or hard coded component markup, which is a violation of our principle of <a href="https://github.com/alphagov/govuk_publishing_components/blob/main/docs/component_principles.md#a-component-is-isolated-when" class="govuk-link">component isolation</a>.</p>
87
105
  <ul class="govuk-list govuk-list--bullet">
88
106
  <% application[:gem_style_references].each do |ref| %>
89
107
  <li>
@@ -95,7 +113,7 @@
95
113
 
96
114
  <% if application[:jquery_references].any? %>
97
115
  <%= render "govuk_publishing_components/components/heading", {
98
- text: "jQuery references",
116
+ text: "jQuery references (#{application[:jquery_references].length})",
99
117
  font_size: "m",
100
118
  margin_bottom: 4,
101
119
  heading_level: 3,
@@ -43,7 +43,9 @@
43
43
  "external": "false",
44
44
  "text": "GOV.UK",
45
45
  "section": "Logo",
46
- "index": 0,
46
+ "index": {
47
+ "index_section": 0,
48
+ },
47
49
  "index_total": navigation_links_length
48
50
  }.to_json %>"
49
51
  >
@@ -128,7 +130,9 @@
128
130
  event_name: "select_content",
129
131
  type: "header menu bar",
130
132
  text: link[:label],
131
- index: 1,
133
+ index: {
134
+ index_section: 1,
135
+ },
132
136
  index_total: 2,
133
137
  section: link[:label]
134
138
  }
@@ -159,7 +163,9 @@
159
163
  "event_name": "select_content",
160
164
  "type": "header menu bar",
161
165
  "text": "Search",
162
- "index": 2,
166
+ "index": {
167
+ "index_section": 2,
168
+ },
163
169
  "index_total": 2,
164
170
  "section": "Search"
165
171
  }.to_json %>"
@@ -238,7 +244,11 @@
238
244
  ga4_link: {
239
245
  "event_name": "navigation",
240
246
  "type": "header menu bar",
241
- "index": "1.#{column_index + 1}.#{index + 1}",
247
+ "index": {
248
+ "index_section": column_index + 1,
249
+ "index_link": index + 1,
250
+ "index_section_count": 4,
251
+ },
242
252
  "index_total": navigation_links_length,
243
253
  "section": column[:label],
244
254
  }
@@ -308,7 +318,11 @@
308
318
  ga4_link: {
309
319
  "event_name": "navigation",
310
320
  "type": "header menu bar",
311
- "index": "2.2.#{index + 1}",
321
+ "index": {
322
+ "index_section": 4,
323
+ "index_link": index + 1,
324
+ "index_section_count": 4,
325
+ },
312
326
  "index_total": navigation_links_length,
313
327
  "section": popular_links_heading,
314
328
  }
@@ -23,8 +23,18 @@
23
23
  data-track-dimension="<%= links[0][:text] %>"
24
24
  data-track-dimension-index="29"
25
25
  data-track-options='{"dimension96" : "<%= links[0][:tracking_id] %>" }'
26
- <% if ga4_tracking %>
27
- data-ga4-link='{"event_name":"navigation", "type":"related content", "index":{"index_link": "1"}, "index_total":"1"}'
26
+ <% if ga4_tracking
27
+ ga4_attributes = {
28
+ event_name: "navigation",
29
+ type: "related content",
30
+ index:{
31
+ "index_link": "1"
32
+ },
33
+ index_total: "1",
34
+ section: "Part of",
35
+ }.to_json
36
+ %>
37
+ data-ga4-link="<%= ga4_attributes %>"
28
38
  <% end %>
29
39
  >
30
40
  <%= links[0][:text] %>
@@ -43,8 +53,18 @@
43
53
  data-track-dimension="<%= link[:text] %>"
44
54
  data-track-dimension-index="29"
45
55
  data-track-options='{"dimension96" : "<%= link[:tracking_id] %>" }'
46
- <% if ga4_tracking %>
47
- data-ga4-link='{"event_name":"navigation", "type":"related content", "index":{"index_link": "<%= index + 1 %>"}, "index_total": "<%= links.length %>"}'
56
+ <% if ga4_tracking
57
+ ga4_attributes = {
58
+ event_name: "navigation",
59
+ type: "related content",
60
+ index:{
61
+ "index_link": (index + 1).to_s
62
+ },
63
+ index_total: (links.length).to_s,
64
+ section: "Part of",
65
+ }.to_json
66
+ %>
67
+ data-ga4-link="<%= ga4_attributes %>"
48
68
  <% end %>
49
69
  >
50
70
  <%= link[:text] %>
@@ -5,6 +5,7 @@ module GovukPublishingComponents
5
5
  @options = options
6
6
 
7
7
  check_id_is_valid(@options[:id]) if @options.include?(:id)
8
+ check_data_attributes_are_valid(@options[:data_attributes]) if @options.include?(:data_attributes)
8
9
  check_classes_are_valid(@options[:classes]) if @options.include?(:classes)
9
10
  check_aria_is_valid(@options[:aria]) if @options.include?(:aria)
10
11
  check_role_is_valid(@options[:role]) if @options.include?(:role)
@@ -13,11 +14,11 @@ module GovukPublishingComponents
13
14
  def all_attributes
14
15
  attributes = {}
15
16
 
16
- attributes[:id] = @options[:id] if @options[:id]
17
- attributes[:data] = @options[:data_attributes] if @options[:data_attributes]
18
- attributes[:aria] = @options[:aria] if @options[:aria]
19
- attributes[:class] = @options[:classes] if @options[:classes]
20
- attributes[:role] = @options[:role] if @options[:role]
17
+ attributes[:id] = @options[:id] unless @options[:id].blank?
18
+ attributes[:data] = @options[:data_attributes] unless @options[:data_attributes].blank?
19
+ attributes[:aria] = @options[:aria] unless @options[:aria].blank?
20
+ attributes[:class] = @options[:classes] unless @options[:classes].blank?
21
+ attributes[:role] = @options[:role] unless @options[:role].blank?
21
22
 
22
23
  attributes
23
24
  end
@@ -33,6 +34,7 @@ module GovukPublishingComponents
33
34
  end
34
35
 
35
36
  def add_data_attribute(attributes)
37
+ check_data_attributes_are_valid(attributes)
36
38
  extend_object(:data_attributes, attributes)
37
39
  end
38
40
 
@@ -49,29 +51,50 @@ module GovukPublishingComponents
49
51
  private
50
52
 
51
53
  def check_id_is_valid(id)
52
- raise(ArgumentError, "Id cannot start with a number or contain whitespace and can only contain letters, digits, `_` and `-`") unless /^[a-zA-Z][\w:-]*$/.match?(id)
54
+ return if id.blank?
55
+
56
+ raise(ArgumentError, "Id (#{id}) cannot start with a number or contain whitespace and can only contain letters, digits, `_` and `-`") unless /^[a-zA-Z][\w:-]*$/.match?(id)
57
+ end
58
+
59
+ def check_data_attributes_are_valid(attributes)
60
+ return if attributes.blank?
61
+
62
+ attributes_keys = attributes.map { |key, _| key.to_s }
63
+ invalid_attributes = attributes_keys.map { |a| a if /^(xml)/.match?(a) || /[A-Z :]+/.match?(a) }.compact
64
+
65
+ raise(ArgumentError, "Data attributes (#{invalid_attributes.join(', ')}) cannot contain capitals, spaces or colons, or start with 'xml'") if invalid_attributes.any?
53
66
  end
54
67
 
55
68
  def check_classes_are_valid(classes)
56
- classes = classes.split(" ")
57
- unless classes.all? { |c| c.start_with?("js-", "gem-c-", "govuk-", "brand--") }
58
- raise(ArgumentError, "Passed classes must be prefixed with `js-`")
69
+ return if classes.blank?
70
+
71
+ class_array = classes.split(" ")
72
+ unless class_array.all? { |c| c.start_with?("js-", "gem-c-", "govuk-", "brand--") }
73
+ raise(ArgumentError, "Classes (#{classes}) must be prefixed with `js-`")
59
74
  end
60
75
  end
61
76
 
62
77
  def check_aria_is_valid(attributes)
78
+ return if attributes.blank?
79
+
63
80
  arias = %w[activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext]
64
81
 
65
- unless attributes.all? { |key, _value| arias.include? key.to_s }
66
- raise(ArgumentError, "Aria attribute is not recognised")
82
+ # array keys are immutable so we have to do this to make a copy, in order to
83
+ # subtract valid aria attributes from invalid in the error message below
84
+ attributes_keys = attributes.map { |key, _| key.to_s }
85
+
86
+ unless attributes_keys.all? { |key| arias.include? key }
87
+ raise(ArgumentError, "Aria attribute (#{(attributes_keys - arias).join(', ')}) not recognised")
67
88
  end
68
89
  end
69
90
 
70
91
  def check_role_is_valid(role)
92
+ return if role.blank?
93
+
71
94
  roles = %w[alert alertdialog application article associationlist associationlistitemkey associationlistitemvalue banner blockquote caption cell code columnheader combobox complementary contentinfo definition deletion dialog directory document emphasis feed figure form group heading img insertion list listitem log main marquee math menu menubar meter navigation none note paragraph presentation region row rowgroup rowheader scrollbar search searchbox separator separator slider spinbutton status strong subscript superscript switch tab table tablist tabpanel term time timer toolbar tooltip tree treegrid treeitem]
72
95
  role = role.split(" ") # can have more than one role
73
96
  unless role.all? { |r| roles.include? r }
74
- raise(ArgumentError, "Role attribute is not recognised")
97
+ raise(ArgumentError, "Role attribute (#{(role - roles).join(', ')}) is not recognised")
75
98
  end
76
99
  end
77
100
 
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "35.1.1".freeze
2
+ VERSION = "35.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: 35.1.1
4
+ version: 35.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: 2023-03-22 00:00:00.000000000 Z
11
+ date: 2023-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: govuk_app_config
@@ -1408,14 +1408,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
1408
1408
  requirements:
1409
1409
  - - ">="
1410
1410
  - !ruby/object:Gem::Version
1411
- version: '2.7'
1411
+ version: '3.0'
1412
1412
  required_rubygems_version: !ruby/object:Gem::Requirement
1413
1413
  requirements:
1414
1414
  - - ">="
1415
1415
  - !ruby/object:Gem::Version
1416
1416
  version: '0'
1417
1417
  requirements: []
1418
- rubygems_version: 3.4.9
1418
+ rubygems_version: 3.4.10
1419
1419
  signing_key:
1420
1420
  specification_version: 4
1421
1421
  summary: A gem to document components in GOV.UK frontend applications