ccs-frontend_helpers 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 294fb84084e25efd871cf66bf4513023648669964b1fbc026aece725bcd64c78
4
- data.tar.gz: cd55ae750739c51a9561871d5d2c782a067ace1b04f7014e3b41d05349db6f68
3
+ metadata.gz: d935d241fb0117c445c9e5a7eaa2cee257c5f7bc1e68457baf347aabf946a664
4
+ data.tar.gz: 4a8328285e0adad683eafbf72d8385ea7b3703ae352eded484eb6595bb8ce136
5
5
  SHA512:
6
- metadata.gz: d64eb288f9595343e58ec37eec080a925928b908273c1880efd409a3cde6f9015567221838496084c03d3799dd54ea7ae10328e4c545d446d0f876b0892efb9c
7
- data.tar.gz: d1c288ab82c3c78b1049a1bf8d580b515d213d52758aedf378799262efa854880eab99e69251e0cf74502bb29af8da7fa965adf6275f8755672896dc49787a43
6
+ metadata.gz: 3e4698ad6bcca9cfc345922d05da7580f8f21c4789ff2631d838001f0cd68090c0039467d95e2af4fee2b279822e9b522bfcc42f9ee198c89f4658e153e9e9ae
7
+ data.tar.gz: 5fb56ee826dc2350d685e6fa888e11e2644bbf199db306a9953174b386e21efd42393db88f62813268218f0a387f15e107f3f010d8d2964690063034808833f2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## [0.3.0] - 2024-04-12
2
+
3
+ Update components to be compatible with GOV.UK Frontend v5.3
4
+
5
+ ### 🆕 New features
6
+
7
+ The following GOV.UK helpers have been added:
8
+
9
+ - Password input
10
+
1
11
  ## [0.2.0] - 2024-03-13
2
12
 
3
13
  ### 💥 Breaking changes
data/Gemfile CHANGED
@@ -7,7 +7,7 @@ gemspec
7
7
 
8
8
  # Gems for building the package
9
9
  gem 'bundler', '~> 2.3'
10
- gem 'rake', '~> 13.1'
10
+ gem 'rake', '~> 13.2'
11
11
 
12
12
  # Gems for testing the package
13
13
  gem 'capybara', '~> 3.40.0'
@@ -19,7 +19,7 @@ gem 'nokogiri-diff', '~> 0.3.0'
19
19
  gem 'rubocop', '~> 1.62'
20
20
  gem 'rubocop-rails', '~> 2.24'
21
21
  gem 'rubocop-rake', '~> 0.6'
22
- gem 'rubocop-rspec', '~> 2.27'
22
+ gem 'rubocop-rspec', '~> 2.29'
23
23
 
24
24
  # Gems for documenting the package
25
25
  gem 'yard', '~> 0.9'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ccs-frontend_helpers (0.2.0)
4
+ ccs-frontend_helpers (0.3.0)
5
5
  rails (>= 6.0)
6
6
 
7
7
  GEM
@@ -85,7 +85,7 @@ GEM
85
85
  public_suffix (>= 2.0.2, < 6.0)
86
86
  ast (2.4.2)
87
87
  base64 (0.2.0)
88
- bigdecimal (3.1.6)
88
+ bigdecimal (3.1.7)
89
89
  builder (3.2.4)
90
90
  capybara (3.40.0)
91
91
  addressable
@@ -112,7 +112,7 @@ GEM
112
112
  irb (1.11.2)
113
113
  rdoc
114
114
  reline (>= 0.4.2)
115
- json (2.7.1)
115
+ json (2.7.2)
116
116
  language_server-protocol (3.17.0.3)
117
117
  loofah (2.22.0)
118
118
  crass (~> 1.0.2)
@@ -125,7 +125,7 @@ GEM
125
125
  marcel (1.0.2)
126
126
  matrix (0.4.2)
127
127
  mini_mime (1.1.5)
128
- minitest (5.22.2)
128
+ minitest (5.22.3)
129
129
  mutex_m (0.2.0)
130
130
  net-imap (0.4.10)
131
131
  date
@@ -152,7 +152,7 @@ GEM
152
152
  stringio
153
153
  public_suffix (5.0.4)
154
154
  racc (1.7.3)
155
- rack (3.0.9.1)
155
+ rack (3.0.10)
156
156
  rack-session (2.0.0)
157
157
  rack (>= 3.0.0)
158
158
  rack-test (2.1.0)
@@ -190,7 +190,7 @@ GEM
190
190
  thor (~> 1.0, >= 1.2.2)
191
191
  zeitwerk (~> 2.6)
192
192
  rainbow (3.1.1)
193
- rake (13.1.0)
193
+ rake (13.2.1)
194
194
  rdoc (6.6.2)
195
195
  psych (>= 4.0.0)
196
196
  regexp_parser (2.9.0)
@@ -227,17 +227,20 @@ GEM
227
227
  rubocop (~> 1.41)
228
228
  rubocop-factory_bot (2.25.1)
229
229
  rubocop (~> 1.41)
230
- rubocop-rails (2.24.0)
230
+ rubocop-rails (2.24.1)
231
231
  activesupport (>= 4.2.0)
232
232
  rack (>= 1.1)
233
233
  rubocop (>= 1.33.0, < 2.0)
234
234
  rubocop-ast (>= 1.31.1, < 2.0)
235
235
  rubocop-rake (0.6.0)
236
236
  rubocop (~> 1.0)
237
- rubocop-rspec (2.27.1)
237
+ rubocop-rspec (2.29.1)
238
238
  rubocop (~> 1.40)
239
239
  rubocop-capybara (~> 2.17)
240
240
  rubocop-factory_bot (~> 2.22)
241
+ rubocop-rspec_rails (~> 2.28)
242
+ rubocop-rspec_rails (2.28.2)
243
+ rubocop (~> 1.40)
241
244
  ruby-progressbar (1.13.0)
242
245
  simplecov (0.22.0)
243
246
  docile (~> 1.1)
@@ -271,12 +274,12 @@ DEPENDENCIES
271
274
  capybara (~> 3.40.0)
272
275
  ccs-frontend_helpers!
273
276
  nokogiri-diff (~> 0.3.0)
274
- rake (~> 13.1)
277
+ rake (~> 13.2)
275
278
  rspec (~> 3.13)
276
279
  rubocop (~> 1.62)
277
280
  rubocop-rails (~> 2.24)
278
281
  rubocop-rake (~> 0.6)
279
- rubocop-rspec (~> 2.27)
282
+ rubocop-rspec (~> 2.29)
280
283
  simplecov (~> 0.21)
281
284
  yard (~> 0.9)
282
285
 
data/README.md CHANGED
@@ -14,6 +14,7 @@ The following table shows the version of CCS Frontend Helpers that you should us
14
14
 
15
15
  | CCS Frontend Helpers Version | Target GOV.UK Frontend Version |
16
16
  | ----------------------------- | ------------------------------ |
17
+ | [0.3.0](https://github.com/tim-s-ccs/ccs-frontend_helpers/releases/tag/v0.3.0) | [5.3.0](https://github.com/alphagov/govuk-frontend/releases/tag/v5.3.0) |
17
18
  | [0.2.0](https://github.com/tim-s-ccs/ccs-frontend_helpers/releases/tag/v0.2.0) | [5.2.0](https://github.com/alphagov/govuk-frontend/releases/tag/v5.2.0) |
18
19
  | [0.1.2](https://github.com/tim-s-ccs/ccs-frontend_helpers/releases/tag/v0.1.2) | [4.7.0](https://github.com/alphagov/govuk-frontend/releases/tag/v4.7.0) |
19
20
 
@@ -37,7 +37,6 @@ module CCS
37
37
  def initialize(navigation: nil, meta: nil, **options)
38
38
  super(**options)
39
39
 
40
- @options[:attributes][:role] = 'contentinfo'
41
40
  @options[:copyright] ||= '© Crown copyright'
42
41
 
43
42
  @navigation = navigation&.map { |navigation_item| Navigation.new(context: @context, **navigation_item) }
@@ -45,7 +45,6 @@ module CCS
45
45
  def initialize(service_authentication_items: nil, navigation: nil, menu_button: nil, service: nil, **options)
46
46
  super(**options)
47
47
 
48
- @options[:attributes][:role] = 'banner'
49
48
  @options[:container_classes] ||= 'govuk-width-container'
50
49
  @options[:homepage_url] ||= 'https://www.crowncommercial.gov.uk'
51
50
 
@@ -0,0 +1,62 @@
1
+ module CCS
2
+ module Components
3
+ module GovUK
4
+ class Field < Base
5
+ class Input < Field
6
+ class CharacterCount
7
+ # = GOV.UK Character count message
8
+ #
9
+ # This is used to generate the character count message
10
+ #
11
+ # @!attribute [r] count_message
12
+ # @return [Hint] Hint with the count message
13
+ # @!attribute [r] after_input
14
+ # @return [String] Text or HTML for after the textarea input
15
+
16
+ class CountMessage
17
+ include ActionView::Context
18
+ include ActionView::Helpers
19
+
20
+ private
21
+
22
+ attr_reader :count_message, :after_input
23
+
24
+ public
25
+
26
+ # @param character_count_attribute [String] the name of the field as it will appear in the textarea
27
+ # @param context [ActionView::Base] the view context
28
+ # @param character_count_options (see CCS::Components::GovUK::Field::Input::CharacterCount.get_character_count_from_group_options)
29
+ # @param after_input [String] Text or HTML that goes after the input
30
+ #
31
+ # @option (see CCS::Components::GovUK::Field::Input::CharacterCount.get_character_count_from_group_options)
32
+
33
+ def initialize(character_count_attribute:, context:, character_count_options:, after_input: nil)
34
+ count_message = character_count_options[:textarea_description] || {}
35
+
36
+ count_message_length = character_count_options[:maxwords] || character_count_options[:maxlength]
37
+ count_message_default = "You can enter up to %<count>s #{character_count_options[:maxwords] ? 'words' : 'characters'}"
38
+
39
+ text = count_message_length ? format(count_message[:count_message] || count_message_default, count: count_message_length) : ''
40
+ classes = "govuk-character-count__message #{count_message[:classes]}".rstrip
41
+
42
+ @count_message = Hint.new(text: text, classes: classes, attributes: { id: "#{character_count_attribute}-info" }, context: context)
43
+ @after_input = after_input
44
+ end
45
+
46
+ # Generates the HTML for the GOV.UK Character count message
47
+ #
48
+ # @return [ActiveSupport::SafeBuffer]
49
+
50
+ def render
51
+ capture do
52
+ concat(count_message.render)
53
+ concat(after_input) if after_input
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,5 +1,5 @@
1
1
  require_relative 'textarea'
2
- require_relative '../../hint'
2
+ require_relative 'character_count/count_message'
3
3
 
4
4
  module CCS
5
5
  module Components
@@ -21,12 +21,9 @@ module CCS
21
21
  # @return [Hash] HTML options for the character count
22
22
 
23
23
  class CharacterCount
24
- include ActionView::Context
25
- include ActionView::Helpers
26
-
27
24
  private
28
25
 
29
- attr_reader :textarea, :textarea_description, :character_count_html_options
26
+ attr_reader :textarea, :textarea_description
30
27
 
31
28
  public
32
29
 
@@ -41,21 +38,10 @@ module CCS
41
38
  def initialize(attribute:, context:, character_count_options: {}, **options)
42
39
  character_count_attribute = options[:form] ? "#{options[:form].object_name}_#{attribute}" : attribute
43
40
 
44
- initialise_textarea(attribute, character_count_attribute, context, options)
45
- initialise_character_count_html_options(character_count_options)
46
- initialise_textarea_description(character_count_attribute, context, character_count_options)
41
+ initialise_textarea(attribute, character_count_attribute, character_count_options, context, options)
47
42
  end
48
43
 
49
- # Generates the HTML for the GOV.UK Character count component
50
- #
51
- # @return [ActiveSupport::SafeBuffer]
52
-
53
- def render
54
- tag.div(**character_count_html_options) do
55
- concat(textarea.render)
56
- concat(textarea_description.render)
57
- end
58
- end
44
+ delegate :render, to: :textarea
59
45
 
60
46
  private
61
47
 
@@ -63,19 +49,23 @@ module CCS
63
49
  #
64
50
  # @param attribute [Symbol] the attribute of the field
65
51
  # @param character_count_attribute [String] the name of the field as it will appear in the textarea
52
+ # @param character_count_options [Hash] options for the character count
66
53
  # @param context [ActionView::Base] the view context
67
54
  # @param options [Hash] options that will be used for the textarea
68
55
  #
69
56
  # @option (see CCS::Components::GovUK::Field::Input::Textarea#initialize)
70
57
 
71
- def initialise_textarea(attribute, character_count_attribute, context, options)
58
+ def initialise_textarea(attribute, character_count_attribute, character_count_options, context, options)
59
+ set_character_count_from_group_options(character_count_options, options)
60
+
72
61
  ((options[:attributes] ||= {})[:aria] ||= {})[:describedby] = [options.dig(:attributes, :aria, :describedby), "#{character_count_attribute}-info"].compact.join(' ')
73
62
  options[:classes] = "govuk-js-character-count #{options[:classes]}".rstrip
74
63
 
75
- @textarea = Textarea.new(attribute: attribute, context: context, **options)
64
+ count_message = CountMessage.new(character_count_attribute: character_count_attribute, context: context, character_count_options: character_count_options, after_input: options.delete(:after_input))
65
+ @textarea = Textarea.new(attribute: attribute, context: context, after_input: count_message.render, **options)
76
66
  end
77
67
 
78
- # Initialises the charcter count options
68
+ # Sets the charcter count form group options
79
69
  #
80
70
  # @param character_count_options [Hash] options for the charcter count
81
71
  #
@@ -91,50 +81,29 @@ module CCS
91
81
  # - +:count_message+ replaced the default text for the count message.
92
82
  # If you want the count number to appear, put %<count>s in the string and it will be replaced with the number
93
83
  # - +classes+ additional CSS classes for the textarea description HTML
94
- # @option character_count_options [Hash] :characters_under_limit Message displayed when the number of characters is under the configured maximum, maxlength
84
+ # @option character_count_options [String] :characters_under_limit Message displayed when the number of characters is under the configured maximum, maxlength
95
85
  # @option character_count_options [String] :characters_at_limit_text Message displayed when the number of characters reaches the configured maximum, maxlength
96
- # @option character_count_options [Hash] :characters_over_limit Message displayed when the number of characters is over the configured maximum, maxlength
97
- # @option character_count_options [Hash] :words_under_limit Message displayed when the number of words is under the configured maximum, maxwords
86
+ # @option character_count_options [String] :characters_over_limit Message displayed when the number of characters is over the configured maximum, maxlength
87
+ # @option character_count_options [String] :words_under_limit Message displayed when the number of words is under the configured maximum, maxwords
98
88
  # @option character_count_options [String] :words_at_limit_text Message displayed when the number of words reaches the configured maximum, maxwords
99
- # @option character_count_options [Hash] :words_over_limit Message displayed when the number of words is over the configured maximum, maxwords
89
+ # @option character_count_options [String] :words_over_limit Message displayed when the number of words is over the configured maximum, maxwords
100
90
 
101
- def initialise_character_count_html_options(character_count_options)
102
- character_count_html_options = { class: 'govuk-character-count', data: { module: 'govuk-character-count' } }
91
+ def set_character_count_from_group_options(character_count_options, options)
92
+ (options[:form_group] ||= {})[:classes] = "govuk-character-count #{options.dig(:form_group, :classes)}".rstrip
93
+ ((options[:form_group][:attributes] ||= {})[:data] ||= {})[:module] = 'govuk-character-count'
103
94
 
104
95
  %i[maxlength threshold maxwords].each do |data_attribute|
105
- character_count_html_options[:data][data_attribute] = character_count_options[data_attribute].to_s if character_count_options[data_attribute]
96
+ options[:form_group][:attributes][:data][data_attribute] = character_count_options[data_attribute].to_s if character_count_options[data_attribute]
106
97
  end
107
98
 
108
- get_chacrter_count_translations(character_count_options).each do |data_attribute, value|
109
- character_count_html_options[:data][data_attribute] = value
99
+ get_chacrter_count_translations(character_count_options) do |data_attribute, value|
100
+ options[:form_group][:attributes][:data][data_attribute] = value
110
101
  end
111
-
112
- @character_count_html_options = character_count_html_options
113
- end
114
-
115
- # Initialises the charcter count textarea description
116
- #
117
- # @param character_count_attribute [String] the name of the field as it will appear in the textarea
118
- # @param context [ActionView::Base] the view context
119
- # @param (see initialise_character_count_html_options)
120
- #
121
- # @option (see initialise_character_count_html_options)
122
-
123
- def initialise_textarea_description(character_count_attribute, context, character_count_options)
124
- textarea_description = character_count_options[:textarea_description] || {}
125
-
126
- textarea_description_length = character_count_options[:maxwords] || character_count_options[:maxlength]
127
- textarea_description_default = "You can enter up to %<count>s #{character_count_options[:maxwords] ? 'words' : 'characters'}"
128
-
129
- text = textarea_description_length ? format(textarea_description[:count_message] || textarea_description_default, count: textarea_description_length) : ''
130
- classes = "govuk-character-count__message #{textarea_description[:classes]}".rstrip
131
-
132
- @textarea_description = Hint.new(text: text, classes: classes, attributes: { id: "#{character_count_attribute}-info" }, context: context)
133
102
  end
134
103
 
135
104
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
136
105
 
137
- # Returns the translation options for character count
106
+ # Generator for the translation options for character count
138
107
  #
139
108
  # @param (see initialise_character_count_html_options)
140
109
  #
@@ -143,24 +112,25 @@ module CCS
143
112
  # @return [Hash]
144
113
 
145
114
  def get_chacrter_count_translations(character_count_options)
146
- character_count_data_options = {}
147
-
148
115
  %i[characters_at_limit words_at_limit].each do |data_attribute|
149
116
  data_attribute_name = :"#{data_attribute}_text"
150
- character_count_data_options[:"i18n.#{data_attribute.to_s.gsub('_', '-')}"] = character_count_options[data_attribute_name] if character_count_options[data_attribute_name]
117
+
118
+ next unless character_count_options[data_attribute_name]
119
+
120
+ yield :"i18n.#{data_attribute.to_s.gsub('_', '-')}", character_count_options[data_attribute_name]
151
121
  end
152
122
 
153
123
  %i[characters_under_limit characters_over_limit words_under_limit words_over_limit].each do |data_attribute|
154
124
  next unless character_count_options[data_attribute]
155
125
 
156
126
  %i[other one].each do |plural_rule|
157
- character_count_data_options[:"i18n.#{data_attribute.to_s.gsub('_', '-')}.#{plural_rule}"] = character_count_options[data_attribute][plural_rule] if character_count_options[data_attribute][plural_rule]
127
+ next unless character_count_options[data_attribute][plural_rule]
128
+
129
+ yield :"i18n.#{data_attribute.to_s.gsub('_', '-')}.#{plural_rule}", character_count_options[data_attribute][plural_rule]
158
130
  end
159
131
  end
160
132
 
161
- character_count_data_options[:'i18n.textarea-description.other'] = character_count_options[:textarea_description][:count_message] if character_count_options.dig(:textarea_description, :count_message) && !(character_count_options[:maxwords] || character_count_options[:maxlength])
162
-
163
- character_count_data_options
133
+ yield :'i18n.textarea-description.other', character_count_options[:textarea_description][:count_message] if character_count_options.dig(:textarea_description, :count_message) && !(character_count_options[:maxwords] || character_count_options[:maxlength])
164
134
  end
165
135
 
166
136
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -0,0 +1,72 @@
1
+ require_relative '../../../button'
2
+
3
+ module CCS
4
+ module Components
5
+ module GovUK
6
+ class Field < Base
7
+ class Input < Field
8
+ class PasswordInput
9
+ # = GOV.UK Password input show/hide button
10
+ #
11
+ # This is used to generate the password input show/hide button
12
+ #
13
+ # @!attribute [r] show_hide_button
14
+ # @return [Button] Show/Hide button
15
+ # @!attribute [r] after_input
16
+ # @return [String] Text or HTML for after the textarea input
17
+
18
+ class ShowHideButton
19
+ include ActionView::Context
20
+ include ActionView::Helpers
21
+ include ActionView::Helpers::FormTagHelper
22
+
23
+ private
24
+
25
+ attr_reader :show_hide_button, :after_input
26
+
27
+ public
28
+
29
+ # @param attribute [String] the name of the field as it will appear in the input
30
+ # @param context [ActionView::Base] the view context
31
+ # @param button [Hash] options for the button
32
+ # @param after_input [String] Text or HTML that goes after the input
33
+ #
34
+ # @option button [String] :classes classes to add to the button
35
+ #
36
+ # @option (see CCS::Components::GovUK::Field::Input::PasswordInput.set_password_input_from_group_options)
37
+
38
+ def initialize(attribute:, context:, button: {}, after_input: nil, **options)
39
+ button[:classes] = "govuk-button--secondary govuk-password-input__toggle govuk-js-password-input-toggle #{button[:classes]}".rstrip
40
+ button[:attributes] = {
41
+ type: :button,
42
+ aria: {
43
+ controls: options.dig(:attributes, :id) || field_id(options[:form]&.object_name, attribute),
44
+ label: options[:show_password_aria_label_text] || 'Show password'
45
+ },
46
+ hidden: {
47
+ value: true,
48
+ optional: true
49
+ }
50
+ }
51
+
52
+ @show_hide_button = Button.new(text: options[:show_password_text] || 'Show', context: context, classes: button[:classes], attributes: button[:attributes])
53
+ @after_input = after_input
54
+ end
55
+
56
+ # Generates the HTML for the GOV.UK Password input show/hide button
57
+ #
58
+ # @return [ActiveSupport::SafeBuffer]
59
+
60
+ def render
61
+ capture do
62
+ concat(show_hide_button.render)
63
+ concat(after_input) if after_input
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,101 @@
1
+ require_relative 'text_input'
2
+ require_relative 'password_input/show_hide_button'
3
+
4
+ module CCS
5
+ module Components
6
+ module GovUK
7
+ class Field < Base
8
+ class Input < Field
9
+ # = GOV.UK Password input
10
+ #
11
+ # This is used for generating the password input component from the
12
+ # {https://design-system.service.gov.uk/components/password-input GDS - Components - Password Input}
13
+ #
14
+ # @!attribute [r] text_input
15
+ # @return [CCS::Components::GovUK::Field::Input::TextInput] Initialised text input component
16
+
17
+ class PasswordInput
18
+ private
19
+
20
+ attr_reader :text_input
21
+
22
+ public
23
+
24
+ # @param (see CCS::Components::GovUK::Field::Input::TextInput#initialize)
25
+ #
26
+ # @option (see CCS::Components::GovUK::Field::Input::TextInput#initialize)
27
+
28
+ def initialize(attribute:, context:, **options)
29
+ set_password_input_from_group_options(options)
30
+
31
+ show_hide_button = ShowHideButton.new(attribute: attribute, context: context, after_input: options.delete(:after_input), **options)
32
+
33
+ options[:attributes] ||= {}
34
+ options[:attributes][:spellcheck] = false
35
+ options[:attributes][:autocapitalize] = 'none'
36
+ options[:attributes][:autocomplete] ||= 'current-password'
37
+
38
+ @text_input = TextInput.new(
39
+ context: context,
40
+ attribute: attribute,
41
+ after_input: show_hide_button.render,
42
+ input_wrapper: {
43
+ classes: 'govuk-password-input__wrapper'
44
+ },
45
+ classes: "govuk-password-input__input govuk-js-password-input-input #{options.delete(:classes)}".rstrip,
46
+ field_type: :password,
47
+ **options
48
+ )
49
+ end
50
+
51
+ delegate :render, to: :text_input
52
+
53
+ private
54
+
55
+ # rubocop:disable Naming/AccessorMethodName
56
+
57
+ # Sets the password input form group options
58
+ #
59
+ # @param options [Hash] options for the password input
60
+ #
61
+ # @option options [String] :show_password_text button text when the password is hidden
62
+ # @option options [String] :hide_password_text button text when the password is visible
63
+ # @option options [String] :show_password_aria_label_text button text exposed to assistive technologies, like screen readers, when the password is hidden
64
+ # @option options [String] :hide_password_aria_label_text button text exposed to assistive technologies, like screen readers, when the password is visible
65
+ # @option options [String] :password_shown_announcement_text announcement made to screen reader users when their password has become visible in plain text
66
+ # @option options [String] :password_hidden_announcement_text announcement made to screen reader users when their password has been obscured and is not visible
67
+
68
+ def set_password_input_from_group_options(options)
69
+ (options[:form_group] ||= {})[:classes] = "govuk-password-input #{options.dig(:form_group, :classes)}".rstrip
70
+ ((options[:form_group][:attributes] ||= {})[:data] ||= {})[:module] = 'govuk-password-input'
71
+
72
+ get_password_input_translations(options) do |data_attribute, value|
73
+ options[:form_group][:attributes][:data][data_attribute] = value
74
+ end
75
+ end
76
+
77
+ # rubocop:enable Naming/AccessorMethodName
78
+
79
+ # Generator for the translation options for password input
80
+ #
81
+ # @param (see initialise_password_input_html_options)
82
+ #
83
+ # @option (see initialise_password_input_html_options)
84
+ #
85
+ # @yield Data attribute key and the value
86
+
87
+ def get_password_input_translations(password_input_options)
88
+ %i[show_password hide_password show_password_aria_label hide_password_aria_label password_shown_announcement password_hidden_announcement].each do |data_attribute|
89
+ data_attribute_name = :"#{data_attribute}_text"
90
+
91
+ next unless password_input_options[data_attribute_name]
92
+
93
+ yield :"i18n.#{data_attribute.to_s.gsub('_', '-')}", password_input_options[data_attribute_name]
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -19,11 +19,13 @@ module CCS
19
19
  # @return [Fix] The initialised prefix
20
20
  # @!attribute [r] suffix
21
21
  # @return [Fix] The initialised suffix
22
+ # @!attribute [r] input_wrapper_html_options
23
+ # @return [Fix] HTML options for the input wrapper
22
24
 
23
25
  class TextInput < Input
24
26
  private
25
27
 
26
- attr_reader :field_type, :value, :prefix, :suffix
28
+ attr_reader :field_type, :value, :prefix, :suffix, :input_wrapper_html_options
27
29
 
28
30
  public
29
31
 
@@ -36,33 +38,41 @@ module CCS
36
38
  # see {CCS::Components::GovUK::Field::Input::TextInput::Fix#initialize Fix#initialize} for more details.
37
39
  # @param suffix [Hash] optional suffix for the input field,
38
40
  # see {CCS::Components::GovUK::Field::Input::TextInput::Fix#initialize Fix#initialize} for more details.
41
+ # @param input_wrapper [Hash] HTML options for the input wrapper
39
42
  #
40
43
  # @option (see CCS::Components::GovUK::Field::Input#initialize)
41
44
 
42
- def initialize(attribute:, field_type: :text, value: nil, prefix: nil, suffix: nil, **options)
45
+ def initialize(attribute:, field_type: :text, value: nil, prefix: nil, suffix: nil, input_wrapper: {}, **options)
43
46
  super(attribute: attribute, **options)
44
47
 
45
48
  @field_type = :"#{field_type}_field"
46
49
  @value = @options[:model] ? @options[:model].send(attribute) : value
47
50
  @prefix = Fix.new(fix: 'pre', context: @context, **prefix) if prefix
48
51
  @suffix = Fix.new(fix: 'suf', context: @context, **suffix) if suffix
52
+ @input_wrapper_html_options = {
53
+ class: "govuk-input__wrapper #{input_wrapper[:classes]}".rstrip
54
+ }.merge(input_wrapper[:attributes] || {})
49
55
  end
50
56
 
51
57
  # rubocop:enable Metrics/ParameterLists
58
+ # rubocop:disable Metrics/AbcSize
52
59
 
53
60
  # Generates the HTML for the GOV.UK Text Input component
54
61
  #
55
62
  # @return [ActiveSupport::SafeBuffer]
56
63
 
57
64
  def render
58
- super() do
59
- text_input_wrapper do
65
+ form_group.render do |display_error_message|
66
+ concat(label.render)
67
+ concat(hint.render) if hint
68
+ concat(display_error_message)
69
+ concat(text_input_wrapper do
60
70
  if options[:form]
61
71
  options[:form].send(field_type, attribute, **options[:attributes])
62
72
  else
63
73
  context.send("#{field_type}_tag", attribute, value, **options[:attributes])
64
74
  end
65
- end
75
+ end)
66
76
  end
67
77
  end
68
78
 
@@ -72,6 +82,8 @@ module CCS
72
82
 
73
83
  private
74
84
 
85
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
86
+
75
87
  # Wrapper method used by {render} to wrap the text input with a prefix or suffix if they exist
76
88
  #
77
89
  # @yield the text input HTML
@@ -79,16 +91,20 @@ module CCS
79
91
  # @return [ActiveSupport::SafeBuffer]
80
92
 
81
93
  def text_input_wrapper
82
- if prefix || suffix
83
- tag.div(class: 'govuk-input__wrapper') do
94
+ if prefix || suffix || before_input || after_input
95
+ tag.div(**input_wrapper_html_options) do
96
+ concat(before_input) if before_input
84
97
  concat(prefix.render) if prefix
85
98
  concat(yield)
86
99
  concat(suffix.render) if suffix
100
+ concat(after_input) if after_input
87
101
  end
88
102
  else
89
103
  yield
90
104
  end
91
105
  end
106
+
107
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
92
108
  end
93
109
  end
94
110
  end
@@ -25,6 +25,8 @@ module CCS
25
25
 
26
26
  # @param (see CCS::Components::GovUK::Field#initialize)
27
27
  # @param label [Hash] attributes for the label, see {CCS::Components::GovUK::Label#initialize Label#initialize} for more details.
28
+ # @param before_input [String] text or HTML to go before the input
29
+ # @param after_input [String] text or HTML to go after the input
28
30
  #
29
31
  # @option (see CCS::Components::GovUK::Field#initialize)
30
32
 
@@ -52,7 +54,9 @@ module CCS
52
54
  concat(label.render)
53
55
  concat(hint.render) if hint
54
56
  concat(display_error_message)
57
+ concat(before_input) if before_input
55
58
  concat(yield)
59
+ concat(after_input) if after_input
56
60
  end
57
61
  end
58
62
  end
@@ -12,17 +12,8 @@ module CCS
12
12
  #
13
13
  # This is used for generating the checkboxes component from the
14
14
  # {https://design-system.service.gov.uk/components/checkboxes GDS - Components - Checkboxes}
15
- #
16
- # @!attribute [r] checkbox_items
17
- # @return [Array<Item::Divider|Item::Checkbox|Item::Checkbox>] An array of the initialised checkbox items
18
15
 
19
16
  class Checkboxes < Inputs
20
- private
21
-
22
- attr_reader :checkbox_items
23
-
24
- public
25
-
26
17
  # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
27
18
 
28
19
  # @param (see CCS::Components::GovUK::Field::Inputs#initialize)
@@ -42,23 +33,11 @@ module CCS
42
33
 
43
34
  checkbox_item_class = @options[:form] ? Item::Checkbox::Form : Inputs::Item::Checkbox::Tag
44
35
 
45
- @checkbox_items = checkbox_items.map { |checkbox_item| checkbox_item[:divider] ? Item::Divider.new(divider: checkbox_item[:divider], type: 'checkboxes') : checkbox_item_class.new(attribute: attribute, form: @options[:form], context: @context, **checkbox_item) }
36
+ @input_items = checkbox_items.map { |checkbox_item| checkbox_item[:divider] ? Item::Divider.new(divider: checkbox_item[:divider], type: 'checkboxes') : checkbox_item_class.new(attribute: attribute, form: @options[:form], context: @context, **checkbox_item) }
46
37
  end
47
38
 
48
39
  # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
49
40
 
50
- # Generates the HTML for the GOV.UK Checkboxes component
51
- #
52
- # @return [ActiveSupport::SafeBuffer]
53
-
54
- def render
55
- super() do
56
- tag.div(**options[:attributes]) do
57
- checkbox_items.each { |checkbox_item| concat(checkbox_item.render) }
58
- end
59
- end
60
- end
61
-
62
41
  # The default attributes for the checkboxes
63
42
 
64
43
  DEFAULT_ATTRIBUTES = { class: 'govuk-checkboxes', data: { module: 'govuk-checkboxes' } }.freeze
@@ -10,17 +10,8 @@ module CCS
10
10
  #
11
11
  # This is used for generating the date input component from the
12
12
  # {https://design-system.service.gov.uk/components/date-input GDS - Components - Date Input}
13
- #
14
- # @!attribute [r] date_input_items
15
- # @return [Array<DateInput::Item>] An array of the initialised date input items
16
13
 
17
14
  class DateInput < Inputs
18
- private
19
-
20
- attr_reader :date_input_items
21
-
22
- public
23
-
24
15
  # @param (see CCS::Components::GovUK::Field::Inputs#initialize)
25
16
  # @param date_items [Array<Hash>] an array of options for the date items.
26
17
  # See {Components::GovUK::Field::Inputs::DateInput::Item#initialize Item#initialize} for details of the items in the array.
@@ -34,19 +25,7 @@ module CCS
34
25
 
35
26
  date_items = default_date_items if date_items.blank?
36
27
 
37
- @date_input_items = date_items.map { |date_input_item| Item.new(attribute: attribute, error_message: @error_message, model: @options[:model], form: @options[:form], context: @context, **date_input_item) }
38
- end
39
-
40
- # Generates the HTML for the GOV.UK date input component
41
- #
42
- # @return [ActiveSupport::SafeBuffer]
43
-
44
- def render
45
- super() do
46
- tag.div(**options[:attributes]) do
47
- date_input_items.each { |date_input_item| concat(date_input_item.render) }
48
- end
49
- end
28
+ @input_items = date_items.map { |date_input_item| Item.new(attribute: attribute, error_message: @error_message, model: @options[:model], form: @options[:form], context: @context, **date_input_item) }
50
29
  end
51
30
 
52
31
  # The default attributes for the date input
@@ -12,14 +12,11 @@ module CCS
12
12
  #
13
13
  # This is used for generating the radios component from the
14
14
  # {https://design-system.service.gov.uk/components/radios GDS - Components - Radios}
15
- #
16
- # @!attribute [r] radio_items
17
- # @return [Array<Item::Divider|Item::Radio|Item::Radio>] An array of the initialised radio items
18
15
 
19
16
  class Radios < Inputs
20
17
  private
21
18
 
22
- attr_reader :radio_items
19
+ attr_reader :input_items
23
20
 
24
21
  public
25
22
 
@@ -40,23 +37,11 @@ module CCS
40
37
 
41
38
  radio_item_class = @options[:form] ? Item::Radio::Form : Inputs::Item::Radio::Tag
42
39
 
43
- @radio_items = radio_items.map { |radio_item| radio_item[:divider] ? Item::Divider.new(divider: radio_item[:divider], type: 'radios') : radio_item_class.new(attribute: attribute, form: @options[:form], context: @context, **radio_item) }
40
+ @input_items = radio_items.map { |radio_item| radio_item[:divider] ? Item::Divider.new(divider: radio_item[:divider], type: 'radios') : radio_item_class.new(attribute: attribute, form: @options[:form], context: @context, **radio_item) }
44
41
  end
45
42
 
46
43
  # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
47
44
 
48
- # Generates the HTML for the GOV.UK Radios component
49
- #
50
- # @return [ActiveSupport::SafeBuffer]
51
-
52
- def render
53
- super() do
54
- tag.div(**options[:attributes]) do
55
- radio_items.each { |radio_item| concat(radio_item.render) }
56
- end
57
- end
58
- end
59
-
60
45
  # The default attributes for the radios
61
46
 
62
47
  DEFAULT_ATTRIBUTES = { class: 'govuk-radios', data: { module: 'govuk-radios' } }.freeze
@@ -14,11 +14,13 @@ module CCS
14
14
  #
15
15
  # @!attribute [r] fieldset
16
16
  # @return [Fieldset] The initialised fieldset
17
+ # @!attribute [r] input_items
18
+ # @return [Array<Item>] An array of the initialised items
17
19
 
18
20
  class Inputs < Field
19
21
  private
20
22
 
21
- attr_reader :fieldset
23
+ attr_reader :fieldset, :input_items
22
24
 
23
25
  public
24
26
 
@@ -66,7 +68,11 @@ module CCS
66
68
  def field_inner_html(display_error_message)
67
69
  concat(hint.render) if hint
68
70
  concat(display_error_message)
69
- concat(yield)
71
+ concat(tag.div(**options[:attributes]) do
72
+ concat(before_input) if before_input
73
+ input_items.each { |input_item| concat(input_item.render) }
74
+ concat(after_input) if after_input
75
+ end)
70
76
  end
71
77
  end
72
78
  end
@@ -18,14 +18,20 @@ module CCS
18
18
  # @return [FormGroup] The initialised form group
19
19
  # @!attribute [r] hint
20
20
  # @return [Hint] The initialised hint
21
+ # @!attribute [r] before_input
22
+ # @return [String] Text or HTML to go before the input
23
+ # @!attribute [r] after_input
24
+ # @return [String] Text or HTML to go after the input
21
25
 
22
26
  class Field < Base
23
27
  private
24
28
 
25
- attr_reader :attribute, :error_message, :form_group, :hint
29
+ attr_reader :attribute, :error_message, :form_group, :hint, :before_input, :after_input
26
30
 
27
31
  public
28
32
 
33
+ # rubocop:disable Metrics/ParameterLists
34
+
29
35
  # @param attribute [String, Symbol] the attribute of the field
30
36
  # @param hint [Hash] attributes for the hint, see {CCS::Components::GovUK::Hint#initialize Hint#initialize} for more details.
31
37
  # If no hint is given then no hint will be rendered
@@ -39,7 +45,7 @@ module CCS
39
45
  # @option options [String] :classes additional CSS classes for the field HTML
40
46
  # @option options [Hash] :attributes ({}) any additional attributes that will added as part of the HTML
41
47
 
42
- def initialize(attribute:, form_group: nil, hint: nil, **options)
48
+ def initialize(attribute:, form_group: nil, hint: nil, before_input: nil, after_input: nil, **options)
43
49
  super(**options)
44
50
 
45
51
  (hint[:attributes] ||= {})[:id] = "#{attribute}-hint" if hint && !hint.dig(:attributes, :id)
@@ -49,8 +55,12 @@ module CCS
49
55
 
50
56
  @form_group = FormGroup.new(attribute: attribute, error_message: @error_message, context: @context, **(form_group || {}))
51
57
  @hint = Hint.new(context: @context, **hint) if hint
58
+ @before_input = before_input
59
+ @after_input = after_input
52
60
  end
53
61
 
62
+ # rubocop:enable Metrics/ParameterLists
63
+
54
64
  # Generates the HTML to wrap arround a GDS form input component
55
65
  #
56
66
  # @yield the field HTML
@@ -37,7 +37,6 @@ module CCS
37
37
  def initialize(navigation: nil, meta: nil, **options)
38
38
  super(**options)
39
39
 
40
- @options[:attributes][:role] = 'contentinfo'
41
40
  @options[:copyright] ||= '© Crown copyright'
42
41
 
43
42
  @navigation = navigation&.map { |navigation_item| Navigation.new(context: @context, **navigation_item) }
@@ -41,7 +41,6 @@ module CCS
41
41
  def initialize(navigation: nil, menu_button: nil, service: nil, **options)
42
42
  super(**options)
43
43
 
44
- @options[:attributes][:role] = 'banner'
45
44
  @options[:container_classes] ||= 'govuk-width-container'
46
45
  @options[:homepage_url] ||= '/'
47
46
  @options[:use_tudor_crown] = true if @options[:use_tudor_crown].nil?
@@ -46,7 +46,6 @@ module CCS
46
46
  block_is_level = pagination_items.blank? && (pagination_previous.present? || pagination_next.present?)
47
47
 
48
48
  @options[:attributes][:class] << ' govuk-pagination--block' if block_is_level
49
- @options[:attributes][:role] = 'navigation'
50
49
  (@options[:attributes][:aria] ||= {})[:label] ||= 'Pagination'
51
50
 
52
51
  @pagination_previous = Increment::Previous.new(block_is_level: block_is_level, form: @options[:form], context: @context, **pagination_previous) if pagination_previous
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../components/govuk/field/input/password_input'
4
+
5
+ module CCS
6
+ module FrontendHelpers
7
+ module GovUKFrontend
8
+ # = GOV.UK Password input
9
+ #
10
+ # This helper is used for generating the password input component from the
11
+ # {https://design-system.service.gov.uk/components/password-input GDS - Components - Password Input}
12
+
13
+ module PasswordInput
14
+ # Generates the HTML for the GOV.UK Password Input component
15
+ #
16
+ # @param (see CCS::Components::GovUK::Input::PasswordInput#initialize)
17
+ #
18
+ # @option (see CCS::Components::GovUK::Input::PasswordInput#initialize)
19
+ #
20
+ # @return (see CCS::Components::GovUK::Input::PasswordInput#render)
21
+
22
+ def govuk_password_input(attribute, **options)
23
+ Components::GovUK::Field::Input::PasswordInput.new(context: self, attribute: attribute, **options).render
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -24,6 +24,7 @@ require_relative 'govuk_frontend/label'
24
24
  require_relative 'govuk_frontend/notification_banner'
25
25
  require_relative 'govuk_frontend/pagination'
26
26
  require_relative 'govuk_frontend/panel'
27
+ require_relative 'govuk_frontend/password_input'
27
28
  require_relative 'govuk_frontend/phase_banner'
28
29
  require_relative 'govuk_frontend/radios'
29
30
  require_relative 'govuk_frontend/select'
@@ -67,6 +68,7 @@ module CCS
67
68
  include NotificationBanner
68
69
  include Pagination
69
70
  include Panel
71
+ include PasswordInput
70
72
  include PhaseBanner
71
73
  include Radios
72
74
  include Select
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CCS
4
4
  module FrontendHelpers
5
- VERSION = '0.2.0'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
data/package.json CHANGED
@@ -5,6 +5,6 @@
5
5
  "author": "CCS",
6
6
  "license": "MIT",
7
7
  "devDependencies": {
8
- "govuk-frontend": "^5.2.0"
8
+ "govuk-frontend": "^5.3.0"
9
9
  }
10
10
  }
data/yarn.lock CHANGED
@@ -2,7 +2,7 @@
2
2
  # yarn lockfile v1
3
3
 
4
4
 
5
- govuk-frontend@^5.2.0:
6
- version "5.2.0"
7
- resolved "https://registry.yarnpkg.com/govuk-frontend/-/govuk-frontend-5.2.0.tgz#f8e0bf98b771b8ee1501fd45bbba24a091f3846d"
8
- integrity sha512-beD3wztHpkKz6JUpPwnwop1ejb4rTFMPLCutKLCIDmUS4BPpW59ggVUfctsRqHd2Zjw9wxljdRdeIJ8AZFyyTw==
5
+ govuk-frontend@^5.3.0:
6
+ version "5.3.0"
7
+ resolved "https://registry.yarnpkg.com/govuk-frontend/-/govuk-frontend-5.3.0.tgz#f9a2b405925beada90d074e17939f9d8ddcd256e"
8
+ integrity sha512-w6yaaDU3nqhVmWJFnOuJKRIUEB/2RrTFGzoA3z5n4cTG9h292EseT/q+JJA/LYTf5IYzeTIVAUbE5fFjUxefiQ==
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ccs-frontend_helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tim-s-ccs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-13 00:00:00.000000000 Z
11
+ date: 2024-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -72,7 +72,10 @@ files:
72
72
  - lib/ccs/components/govuk/field.rb
73
73
  - lib/ccs/components/govuk/field/input.rb
74
74
  - lib/ccs/components/govuk/field/input/character_count.rb
75
+ - lib/ccs/components/govuk/field/input/character_count/count_message.rb
75
76
  - lib/ccs/components/govuk/field/input/file_upload.rb
77
+ - lib/ccs/components/govuk/field/input/password_input.rb
78
+ - lib/ccs/components/govuk/field/input/password_input/show_hide_button.rb
76
79
  - lib/ccs/components/govuk/field/input/select.rb
77
80
  - lib/ccs/components/govuk/field/input/text_input.rb
78
81
  - lib/ccs/components/govuk/field/input/text_input/fix.rb
@@ -174,6 +177,7 @@ files:
174
177
  - lib/ccs/frontend_helpers/govuk_frontend/notification_banner.rb
175
178
  - lib/ccs/frontend_helpers/govuk_frontend/pagination.rb
176
179
  - lib/ccs/frontend_helpers/govuk_frontend/panel.rb
180
+ - lib/ccs/frontend_helpers/govuk_frontend/password_input.rb
177
181
  - lib/ccs/frontend_helpers/govuk_frontend/phase_banner.rb
178
182
  - lib/ccs/frontend_helpers/govuk_frontend/radios.rb
179
183
  - lib/ccs/frontend_helpers/govuk_frontend/select.rb