ccs-frontend_helpers 0.1.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -3
  3. data/CHANGELOG.md +40 -0
  4. data/Gemfile +7 -6
  5. data/Gemfile.lock +121 -114
  6. data/README.md +12 -0
  7. data/lib/ccs/components/ccs/footer.rb +0 -1
  8. data/lib/ccs/components/ccs/header.rb +0 -1
  9. data/lib/ccs/components/govuk/accordion/section/content.rb +1 -1
  10. data/lib/ccs/components/govuk/accordion.rb +11 -0
  11. data/lib/ccs/components/govuk/button.rb +4 -1
  12. data/lib/ccs/components/govuk/cookie_banner/action.rb +1 -0
  13. data/lib/ccs/components/govuk/cookie_banner/message.rb +1 -1
  14. data/lib/ccs/components/govuk/details.rb +1 -1
  15. data/lib/ccs/components/govuk/error_message.rb +5 -2
  16. data/lib/ccs/components/govuk/exit_this_page.rb +79 -0
  17. data/lib/ccs/components/govuk/field/input/character_count/count_message.rb +62 -0
  18. data/lib/ccs/components/govuk/field/input/character_count.rb +55 -42
  19. data/lib/ccs/components/govuk/field/input/password_input/show_hide_button.rb +72 -0
  20. data/lib/ccs/components/govuk/field/input/password_input.rb +101 -0
  21. data/lib/ccs/components/govuk/field/input/select.rb +2 -2
  22. data/lib/ccs/components/govuk/field/input/text_input.rb +23 -7
  23. data/lib/ccs/components/govuk/field/input.rb +4 -0
  24. data/lib/ccs/components/govuk/field/inputs/checkboxes.rb +8 -28
  25. data/lib/ccs/components/govuk/field/inputs/date_input.rb +4 -25
  26. data/lib/ccs/components/govuk/field/inputs/item/checkbox.rb +1 -13
  27. data/lib/ccs/components/govuk/field/inputs/item/radio.rb +1 -13
  28. data/lib/ccs/components/govuk/field/inputs/item.rb +24 -10
  29. data/lib/ccs/components/govuk/field/inputs/radios.rb +7 -23
  30. data/lib/ccs/components/govuk/field/inputs.rb +31 -7
  31. data/lib/ccs/components/govuk/field.rb +12 -2
  32. data/lib/ccs/components/govuk/fieldset.rb +1 -1
  33. data/lib/ccs/components/govuk/footer/meta.rb +1 -1
  34. data/lib/ccs/components/govuk/footer.rb +1 -2
  35. data/lib/ccs/components/govuk/header/navigation.rb +4 -2
  36. data/lib/ccs/components/govuk/header.rb +26 -8
  37. data/lib/ccs/components/govuk/pagination/increment/next.rb +6 -3
  38. data/lib/ccs/components/govuk/pagination/increment/previous.rb +6 -3
  39. data/lib/ccs/components/govuk/pagination/increment.rb +11 -3
  40. data/lib/ccs/components/govuk/pagination/item.rb +1 -1
  41. data/lib/ccs/components/govuk/pagination.rb +2 -3
  42. data/lib/ccs/components/govuk/summary_list/action/link.rb +18 -3
  43. data/lib/ccs/components/govuk/summary_list/card/actions.rb +3 -2
  44. data/lib/ccs/components/govuk/summary_list/card.rb +1 -1
  45. data/lib/ccs/components/govuk/summary_list/row/actions.rb +3 -2
  46. data/lib/ccs/components/govuk/summary_list/row.rb +7 -2
  47. data/lib/ccs/components/govuk/summary_list.rb +1 -1
  48. data/lib/ccs/components/govuk/tabs.rb +5 -3
  49. data/lib/ccs/components/govuk/task_list/item/status.rb +64 -0
  50. data/lib/ccs/components/govuk/task_list/item/title.rb +54 -0
  51. data/lib/ccs/components/govuk/task_list/item.rb +75 -0
  52. data/lib/ccs/components/govuk/task_list.rb +52 -0
  53. data/lib/ccs/components/govuk/warning_text.rb +1 -1
  54. data/lib/ccs/frontend_helpers/govuk_frontend/character_count.rb +1 -1
  55. data/lib/ccs/frontend_helpers/govuk_frontend/error_message.rb +1 -1
  56. data/lib/ccs/frontend_helpers/govuk_frontend/exit_this_page.rb +28 -0
  57. data/lib/ccs/frontend_helpers/govuk_frontend/password_input.rb +28 -0
  58. data/lib/ccs/frontend_helpers/govuk_frontend/task_list.rb +28 -0
  59. data/lib/ccs/frontend_helpers/govuk_frontend.rb +6 -0
  60. data/lib/ccs/frontend_helpers/version.rb +1 -1
  61. data/package.json +10 -0
  62. data/yarn.lock +8 -0
  63. metadata +15 -2
@@ -0,0 +1,79 @@
1
+ require_relative '../base'
2
+ require_relative 'button'
3
+
4
+ module CCS
5
+ module Components
6
+ module GovUK
7
+ # = GOV.UK Exit this page
8
+ #
9
+ # This is used to generate the exit this page component from the
10
+ # {https://design-system.service.gov.uk/components/exit-this-page GDS - Components - Exit this page}
11
+ #
12
+ # @!attribute [r] text
13
+ # @return [String] Text for the exit this page
14
+ # @!attribute [r] redirect_url
15
+ # @return [String] The redirect_url for the exit this page
16
+
17
+ class ExitThisPage < Base
18
+ include ActionView::Context
19
+ include ActionView::Helpers
20
+
21
+ private
22
+
23
+ attr_reader :text, :redirect_url
24
+
25
+ public
26
+
27
+ # @param text [String] the text for the exit this page
28
+ # @param redirect_url [String] the href for the exit this page
29
+ # @param options [Hash] options that will be used in customising the HTML
30
+ #
31
+ # @option options [String] :classes additional CSS classes for the exit this page HTML
32
+ # @option options [String] :activated_text Text announced by screen readers when Exit this Page has been activated via the keyboard shortcut. Defaults to "Loading."
33
+ # @option options [String] :timed_out_text Text announced by screen readers when the keyboard shortcut has timed out without successful activation. Defaults to "Exit this page expired."
34
+ # @option options [String] :press_two_more_times_text Text announced by screen readers when the user must press Shift two more times to activate the button. Defaults to "Shift, press 2 more times to exit."
35
+ # @option options [String] :press_one_more_time_text Text announced by screen readers when the user must press Shift one more time to activate the button. Defaults to "Shift, press 1 more time to exit."
36
+ # @option options [Hash] :attributes ({}) any additional attributes that will added as part of the HTML
37
+
38
+ def initialize(text: nil, redirect_url: nil, **options)
39
+ super(**options)
40
+
41
+ @text = text || default_text
42
+ @redirect_url = redirect_url || 'https://www.bbc.co.uk/weather'
43
+
44
+ %i[activated timed_out press_two_more_times press_one_more_time].each do |data_attribute|
45
+ data_attribute_name = :"#{data_attribute}_text"
46
+ @options[:attributes][:data][:"i18n.#{data_attribute.to_s.gsub('_', '-')}"] = options[data_attribute_name] if options[data_attribute_name]
47
+ end
48
+ end
49
+
50
+ # Generates the HTML for the GOV.UK Exit this page component
51
+ #
52
+ # @return [ActiveSupport::SafeBuffer]
53
+
54
+ def render
55
+ tag.div(**options[:attributes]) do
56
+ Button.new(text: text, href: redirect_url, context: context, classes: 'govuk-button--warning govuk-exit-this-page__button govuk-js-exit-this-page-button', attributes: { rel: 'nofollow noreferrer' }).render
57
+ end
58
+ end
59
+
60
+ # The default attributes for the exit this page
61
+
62
+ DEFAULT_ATTRIBUTES = { class: 'govuk-exit-this-page', data: { module: 'govuk-exit-this-page' } }.freeze
63
+
64
+ private
65
+
66
+ # Generates the default HTML for the GOV.UK exit this page component
67
+ #
68
+ # @return [ActiveSupport::SafeBuffer]
69
+
70
+ def default_text
71
+ capture do
72
+ concat(tag.span('Emergency', class: 'govuk-visually-hidden'))
73
+ concat(' Exit this page')
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -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
@@ -15,18 +15,15 @@ module CCS
15
15
  #
16
16
  # @!attribute [r] textarea
17
17
  # @return [Textarea] The initialised textarea
18
- # @!attribute [r] fallback_hint
19
- # @return [Hint] The initialised character count fallback hint
18
+ # @!attribute [r] textarea_description
19
+ # @return [Hint] The initialised character count textarea description
20
20
  # @!attribute [r] character_count_html_options
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, :fallback_hint, :character_count_html_options
26
+ attr_reader :textarea, :textarea_description
30
27
 
31
28
  public
32
29
 
@@ -38,24 +35,13 @@ module CCS
38
35
  #
39
36
  # @option (see initialise_character_count_html_options)
40
37
 
41
- def initialize(attribute:, character_count_options:, context:, **options)
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_fallback_hint(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(fallback_hint.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
- options[:classes] = "#{options[:classes]} govuk-js-character-count".lstrip
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
  #
@@ -87,40 +77,63 @@ module CCS
87
77
  # If +maxwords+ is provided, the +maxlength+ option will be ignored.
88
78
  # @option character_count_options [String] :threshold the percentage value of the limit at which point the count message is displayed.
89
79
  # If this attribute is set, the count message will be hidden by default.
90
- # @option character_count_options [Hash] :fallback_hint ({}) additional parameters that will be used to create the hint containing the character count text:
80
+ # @option character_count_options [Hash] :textarea_description ({}) additional parameters that will be used to create the hint containing the character count text:
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
- # - +classes+ additional CSS classes for the fallback hint HTML
94
-
95
- def initialise_character_count_html_options(character_count_options)
96
- character_count_html_options = { class: 'govuk-character-count', data: { module: 'govuk-character-count' } }
83
+ # - +classes+ additional CSS classes for the textarea description HTML
84
+ # @option character_count_options [String] :characters_under_limit Message displayed when the number of characters is under the configured maximum, maxlength
85
+ # @option character_count_options [String] :characters_at_limit_text Message displayed when the number of characters reaches the configured maximum, maxlength
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
88
+ # @option character_count_options [String] :words_at_limit_text Message displayed when the number of words reaches 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
90
+
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'
97
94
 
98
95
  %i[maxlength threshold maxwords].each do |data_attribute|
99
- 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]
100
97
  end
101
98
 
102
- @character_count_html_options = character_count_html_options
99
+ get_chacrter_count_translations(character_count_options) do |data_attribute, value|
100
+ options[:form_group][:attributes][:data][data_attribute] = value
101
+ end
103
102
  end
104
103
 
105
- # Initialises the charcter count fall back hint
104
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
105
+
106
+ # Generator for the translation options for character count
106
107
  #
107
- # @param character_count_attribute [String] the name of the field as it will appear in the textarea
108
- # @param context [ActionView::Base] the view context
109
108
  # @param (see initialise_character_count_html_options)
110
109
  #
111
110
  # @option (see initialise_character_count_html_options)
111
+ #
112
+ # @return [Hash]
112
113
 
113
- def initialise_fallback_hint(character_count_attribute, context, character_count_options)
114
- fallback_hint = character_count_options[:fallback_hint] || {}
114
+ def get_chacrter_count_translations(character_count_options)
115
+ %i[characters_at_limit words_at_limit].each do |data_attribute|
116
+ data_attribute_name = :"#{data_attribute}_text"
115
117
 
116
- fallback_hint_length = character_count_options[:maxwords] || character_count_options[:maxlength]
117
- fallback_hint_default = "You can enter up to %<count>s #{character_count_options[:maxwords] ? 'words' : 'characters'}"
118
+ next unless character_count_options[data_attribute_name]
119
+
120
+ yield :"i18n.#{data_attribute.to_s.gsub('_', '-')}", character_count_options[data_attribute_name]
121
+ end
118
122
 
119
- text = format(fallback_hint[:count_message] || fallback_hint_default, count: fallback_hint_length)
120
- classes = "#{fallback_hint[:classes]} govuk-character-count__message".lstrip
123
+ %i[characters_under_limit characters_over_limit words_under_limit words_over_limit].each do |data_attribute|
124
+ next unless character_count_options[data_attribute]
121
125
 
122
- @fallback_hint = Hint.new(text: text, classes: classes, attributes: { id: "#{character_count_attribute}-info" }, context: context)
126
+ %i[other one].each do |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]
130
+ end
131
+ end
132
+
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])
123
134
  end
135
+
136
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
124
137
  end
125
138
  end
126
139
  end
@@ -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
@@ -38,8 +38,8 @@ module CCS
38
38
  @items = items.map do |item|
39
39
  [
40
40
  item[:text] || item[:value],
41
- item[:value],
42
- (item[:attributes] || {})
41
+ item[:value].nil? ? item[:text] : item[:value],
42
+ item[:attributes] || {}
43
43
  ]
44
44
  end
45
45
  @selected = @options[:model] ? @options[:model].send(attribute) : selected
@@ -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,18 +12,9 @@ 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
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
17
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
27
18
 
28
19
  # @param (see CCS::Components::GovUK::Field::Inputs#initialize)
29
20
  # @param checkbox_items [Array<Hash>] an array of options for the checkboxes.
@@ -34,29 +25,18 @@ module CCS
34
25
  def initialize(attribute:, checkbox_items:, **options)
35
26
  super(attribute: attribute, **options)
36
27
 
37
- if @options[:model] || @options[:form]
38
- values = (@options[:model] || @options[:form].object).send(attribute) || []
39
- checkbox_items.each { |checkbox_item| checkbox_item[:checked] = values.include?(checkbox_item[:value]) }
40
- end
28
+ @options[:values] ||= []
29
+ @options[:values] = (@options[:model] || @options[:form].object).send(attribute) || [] if @options[:model] || @options[:form]
30
+
31
+ checkbox_items.each { |checkbox_item| checkbox_item[:checked] = @options[:values].include?(checkbox_item[:value]) } if @options[:values].any?
32
+ checkbox_items.each { |checkbox_item| set_described_by(checkbox_item, @attribute, @error_message, @hint&.send(:options)) } unless @fieldset
41
33
 
42
34
  checkbox_item_class = @options[:form] ? Item::Checkbox::Form : Inputs::Item::Checkbox::Tag
43
35
 
44
- @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) }
45
37
  end
46
38
 
47
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
48
-
49
- # Generates the HTML for the GOV.UK Checkboxes component
50
- #
51
- # @return [ActiveSupport::SafeBuffer]
52
-
53
- def render
54
- super() do
55
- tag.div(**options[:attributes]) do
56
- checkbox_items.each { |checkbox_item| concat(checkbox_item.render) }
57
- end
58
- end
59
- end
39
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
60
40
 
61
41
  # The default attributes for the checkboxes
62
42