govuk_design_system_formbuilder 0.7.9 → 0.7.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +52 -18
  3. data/lib/govuk_design_system_formbuilder.rb +19 -4
  4. data/lib/govuk_design_system_formbuilder/base.rb +54 -17
  5. data/lib/govuk_design_system_formbuilder/builder.rb +147 -93
  6. data/lib/govuk_design_system_formbuilder/containers/check_boxes_fieldset.rb +28 -0
  7. data/lib/govuk_design_system_formbuilder/containers/fieldset.rb +3 -9
  8. data/lib/govuk_design_system_formbuilder/containers/radio_buttons_fieldset.rb +29 -0
  9. data/lib/govuk_design_system_formbuilder/elements/check_boxes/collection.rb +62 -0
  10. data/lib/govuk_design_system_formbuilder/elements/check_boxes/collection_check_box.rb +21 -7
  11. data/lib/govuk_design_system_formbuilder/elements/check_boxes/fieldset_check_box.rb +75 -0
  12. data/lib/govuk_design_system_formbuilder/elements/check_boxes/hint.rb +9 -17
  13. data/lib/govuk_design_system_formbuilder/elements/check_boxes/label.rb +5 -4
  14. data/lib/govuk_design_system_formbuilder/elements/date.rb +18 -14
  15. data/lib/govuk_design_system_formbuilder/elements/error_message.rb +6 -4
  16. data/lib/govuk_design_system_formbuilder/elements/error_summary.rb +23 -8
  17. data/lib/govuk_design_system_formbuilder/elements/file.rb +40 -0
  18. data/lib/govuk_design_system_formbuilder/elements/hint.rb +1 -1
  19. data/lib/govuk_design_system_formbuilder/elements/input.rb +4 -12
  20. data/lib/govuk_design_system_formbuilder/elements/label.rb +16 -6
  21. data/lib/govuk_design_system_formbuilder/elements/radios/collection.rb +55 -0
  22. data/lib/govuk_design_system_formbuilder/elements/radios/collection_radio_button.rb +48 -0
  23. data/lib/govuk_design_system_formbuilder/elements/radios/{fieldset_radio.rb → fieldset_radio_button.rb} +17 -8
  24. data/lib/govuk_design_system_formbuilder/elements/select.rb +51 -0
  25. data/lib/govuk_design_system_formbuilder/elements/submit.rb +21 -13
  26. data/lib/govuk_design_system_formbuilder/elements/text_area.rb +4 -8
  27. data/lib/govuk_design_system_formbuilder/version.rb +1 -1
  28. metadata +32 -12
  29. data/lib/govuk_design_system_formbuilder/elements/radios/collection_radio.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a58527f914ed7e0cef5f178663fd7969e4fd2cc0b6fa631f0c6e370aac3430e
4
- data.tar.gz: 93c8461e3a90d144f477a1fa79b8082c8679d34aa0a2473f89ea693a01836c8a
3
+ metadata.gz: 73b7bd429e21b82e45676784581f4fe11b9416f64ef2b91352e8eebdfab59137
4
+ data.tar.gz: 7cdabd663e9355585c53102a15269af7771bac0cbcd4c0c3a6c679d231505a66
5
5
  SHA512:
6
- metadata.gz: ffdbdd1aae03e6514927a6daeecc215e70b3bfd653491860b4ce148359689ae00d90cb35aa529b53016a64c89d8e84fe0678335b47055dad7089b930304f6ac6
7
- data.tar.gz: ce348d7c0a8cc1aee7dda9297b64a3389e6d7d136ba422f54e155d7e14786634b591de980744f68f04d1c20971026dffd94c16931aab24fbcb87e7fa96174987
6
+ metadata.gz: 8d770e843277f1d75dc2c1dbe3948f6213188e11329290a545812a272ee9a2fc7223101410ca94251af83c8d4548916d9d9c3cac9de837525fdfaa9414401e3b
7
+ data.tar.gz: bc8fe7c54322289504f46bfdbdb00615b938c9dda38ce6b89e822042943e1f4fe3bf503f856339499f7a6da243b0465b647ad33c089d23085dc2d9c17c35075f
data/README.md CHANGED
@@ -1,37 +1,68 @@
1
1
  # GOV.UK Design System Form Builder for Rails
2
2
 
3
+ [![Build Status](https://travis-ci.com/DFE-Digital/govuk_design_system_formbuilder.svg?branch=master)](https://travis-ci.com/DFE-Digital/govuk_design_system_formbuilder)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/fde73b5dc9476197281b/maintainability)](https://codeclimate.com/github/DFE-Digital/govuk_design_system_formbuilder/maintainability)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/fde73b5dc9476197281b/test_coverage)](https://codeclimate.com/github/DFE-Digital/govuk_design_system_formbuilder/test_coverage)
6
+
7
+ This gem provides a easy-to-use form builder that generates forms that are
8
+ fully-compliant with the [GOV.UK Design System](https://design-system.service.gov.uk/),
9
+ minimising the amount of markup you need to write.
10
+
11
+ In addition to the basic markup, the more-advanced functionality of the Design
12
+ System is exposed via the API. Adding [JavaScript-enhanced word count
13
+ checking](https://www.rubydoc.info/gems/govuk_design_system_formbuilder/GOVUKDesignSystemFormBuilder/Builder#govuk_text_area-instance_method)
14
+ to text areas or [setting the size and weight of
15
+ labels](https://www.rubydoc.info/gems/govuk_design_system_formbuilder/GOVUKDesignSystemFormBuilder/Builder#govuk_text_field-instance_method)
16
+ on text fields requires only a single argument.
17
+
18
+ If you're still not sure what a form builder is or how it works, don't worry!
19
+ [This screencast](https://www.youtube.com/watch?v=PhoFZ0qXAlA) should give you
20
+ an idea of what's on offer 😅
21
+
3
22
  ## What's included
4
23
 
5
- * 100% compatibility with the [GOV.UK Design System](https://design-system.service.gov.uk/)
24
+ * 100% compatibility with the GOV.UK Design System
6
25
  * Full control of labels, hints, fieldsets and legends
7
26
  * No overwriting of Rails' default form helpers
8
27
  * Automatic ARIA associations between hints, errors and inputs
9
- * Most helpers take a block for arbitrary content
28
+ * Most helpers take blocks for arbitrary content
10
29
  * Additional params for programmatically adding hints to check box and radio
11
30
  button collections
12
31
  * No external dependencies
32
+ * [Extensive documentation](https://www.rubydoc.info/gems/govuk_design_system_formbuilder/GOVUKDesignSystemFormBuilder/Builder)
33
+ * An exhaustive test suite
13
34
 
14
35
  ## Installation
15
36
 
16
37
  You can install the form builder gem by running the `gem install
17
38
  govuk_design_system_formbuilder` or by adding the following line
18
- to your `Gemfile`
39
+ to your `Gemfile`:
19
40
 
20
41
  ```sh
21
42
  gem 'govuk_design_system_formbuilder'
22
43
  ```
23
44
 
45
+ To make full use of this tool, you will need a Rails application with the latest [GOV.UK
46
+ Frontend](https://github.com/alphagov/govuk-frontend) assets installed and
47
+ configured.
48
+
49
+ To get up and running quickly and easily try kickstarting your project with a
50
+ pre-configured template:
51
+
52
+ * [DfE Boilerplate](https://github.com/DFE-Digital/govuk-rails-boilerplate)
53
+ * [MoJ Rails Template](https://github.com/ministryofjustice/moj_rails_template)
54
+
24
55
  ## Setup
25
56
 
26
57
  To use the form builder in an ad hoc basis you can specify it
27
- as an argument to `form_for`
28
-
58
+ as an argument to `form_for` or `form_with`:
29
59
 
30
60
  ```slim
31
61
  = form_for @some_object, builder: GOVUKDesignSystemFormBuilder::FormBuilder do |f|
62
+ ...
32
63
  ```
33
64
 
34
- To set it globally, just add this to your `ApplicationController`
65
+ To set it globally, just add this line to your `ApplicationController`:
35
66
 
36
67
  ```ruby
37
68
  class ApplicationController < ActionController::Base
@@ -44,16 +75,16 @@ Now we can get started! 🎉
44
75
  ```slim
45
76
  = form_for @person do |f|
46
77
 
47
- = f.govuk_text_field :full_name, label: { text: 'Your full name' }
78
+ = f.govuk_text_field :full_name, label: { text: "Your full name" }
48
79
 
49
- = f.govuk_number_field :age, label: { text: 'Age' }
80
+ = f.govuk_number_field :age, label: { text: "Age" }
50
81
 
51
82
  = f.govuk_collection_select :department_id,
52
83
  @departments,
53
84
  :id,
54
85
  :name,
55
86
  :description,
56
- label: { text: 'Which department do you work for?' },
87
+ label: { text: "Which department do you work for?" },
57
88
  hint_text: "If you don't know ask your manager" }
58
89
 
59
90
  = f.govuk_submit 'Away we go!'
@@ -63,25 +94,28 @@ Now we can get started! 🎉
63
94
 
64
95
  The form builder is covered by RSpec, to run all the tests first ensure that
65
96
  all of the development and testing prerequisite gems are installed. At the root
66
- of a freshly-cloned repo run
97
+ of a freshly-cloned repo run:
67
98
 
68
99
  ```sh
69
100
  bundle
70
101
  ```
71
102
 
72
- Now, if everything was successful, run RSpec
103
+ Now, if everything was successful, run RSpec:
73
104
 
74
105
  ```sh
75
106
  rspec -fd
76
107
  ```
77
108
 
109
+ ## Contributing
110
+
111
+ Bug reports and feature requests are most welcome, please raise an issue or
112
+ submit a pull request.
113
+
114
+ Currently we're using [GOVUK Lint](https://github.com/alphagov/govuk-lint) to
115
+ ensure code meets the GOV.UK guidelines. Please ensure that any PRs also adhere
116
+ to this standard.
117
+
78
118
  ## Thanks
79
119
 
80
120
  This project was inspired by [MoJ's GovukElementsFormBuilder](https://github.com/ministryofjustice/govuk_elements_form_builder),
81
- but tackles some problems in a different manner. It provides the following
82
- advantages by providing:
83
-
84
- * no reliance on a custom proxy/block buffer
85
- * idiomatic Ruby
86
- * a modular codebase
87
- * a more-robust test suite
121
+ but is leaner, more modular and written in a more idiomatic style.
@@ -6,19 +6,29 @@ require 'govuk_design_system_formbuilder/elements/hint'
6
6
  require 'govuk_design_system_formbuilder/elements/label'
7
7
  require 'govuk_design_system_formbuilder/elements/input'
8
8
  require 'govuk_design_system_formbuilder/elements/date'
9
- require 'govuk_design_system_formbuilder/elements/radios/collection_radio'
10
- require 'govuk_design_system_formbuilder/elements/radios/fieldset_radio'
9
+ require 'govuk_design_system_formbuilder/elements/select'
10
+ require 'govuk_design_system_formbuilder/elements/submit'
11
+ require 'govuk_design_system_formbuilder/elements/text_area'
12
+ require 'govuk_design_system_formbuilder/elements/file'
13
+
14
+ require 'govuk_design_system_formbuilder/elements/radios/collection'
15
+ require 'govuk_design_system_formbuilder/elements/radios/collection_radio_button'
16
+ require 'govuk_design_system_formbuilder/elements/radios/fieldset_radio_button'
17
+
18
+ require 'govuk_design_system_formbuilder/elements/check_boxes/collection'
11
19
  require 'govuk_design_system_formbuilder/elements/check_boxes/collection_check_box'
20
+ require 'govuk_design_system_formbuilder/elements/check_boxes/fieldset_check_box'
12
21
  require 'govuk_design_system_formbuilder/elements/check_boxes/label'
13
22
  require 'govuk_design_system_formbuilder/elements/check_boxes/hint'
23
+
14
24
  require 'govuk_design_system_formbuilder/elements/error_message'
15
25
  require 'govuk_design_system_formbuilder/elements/error_summary'
16
- require 'govuk_design_system_formbuilder/elements/submit'
17
- require 'govuk_design_system_formbuilder/elements/text_area'
18
26
 
27
+ require 'govuk_design_system_formbuilder/containers/check_boxes_fieldset'
19
28
  require 'govuk_design_system_formbuilder/containers/form_group'
20
29
  require 'govuk_design_system_formbuilder/containers/fieldset'
21
30
  require 'govuk_design_system_formbuilder/containers/radios'
31
+ require 'govuk_design_system_formbuilder/containers/radio_buttons_fieldset'
22
32
  require 'govuk_design_system_formbuilder/containers/check_boxes'
23
33
  require 'govuk_design_system_formbuilder/containers/character_count'
24
34
 
@@ -28,4 +38,9 @@ module GOVUKDesignSystemFormBuilder
28
38
 
29
39
  include GOVUKDesignSystemFormBuilder::Builder
30
40
  end
41
+
42
+ # Disable Rails' div.field_with_error wrapper
43
+ ActionView::Base.field_error_proc = Proc.new do |html_tag, _instance|
44
+ html_tag.html_safe
45
+ end
31
46
  end
@@ -6,12 +6,41 @@ module GOVUKDesignSystemFormBuilder
6
6
  @attribute_name = attribute_name
7
7
  end
8
8
 
9
- def html
10
- fail 'should be overridden'
9
+ def hint_element
10
+ @hint_element ||= Elements::Hint.new(@builder, @object_name, @attribute_name, @hint_text)
11
+ end
12
+
13
+ def error_element
14
+ @error_element ||= Elements::ErrorMessage.new(@builder, @object_name, @attribute_name)
15
+ end
16
+
17
+ def label_element
18
+ @label_element ||= Elements::Label.new(@builder, @object_name, @attribute_name, @label)
19
+ end
20
+
21
+ # returns the id value used for the input
22
+ #
23
+ # @note field_id is overridden so that the error summary can link to the
24
+ # correct element.
25
+ #
26
+ # It's straightforward for inputs with a single element (like a textarea
27
+ # or text input) but the GOV.UK Design System requires that the error
28
+ # summary link to the first checkbox or radio in a list, so additional
29
+ # logic is requred
30
+ #
31
+ # @return [String] the element's +id+
32
+ # @see https://design-system.service.gov.uk/components/error-summary/#linking-from-the-error-summary-to-each-answer
33
+ # GOV.UK linking to elements from the error summary
34
+ def field_id(link_errors: false)
35
+ if link_errors && has_errors?
36
+ build_id('field-error', include_value: false)
37
+ else
38
+ build_id('field')
39
+ end
11
40
  end
12
41
 
13
42
  def hint_id
14
- return nil unless @hint_text.present?
43
+ return nil if @hint_text.blank?
15
44
 
16
45
  build_id('hint')
17
46
  end
@@ -26,35 +55,43 @@ module GOVUKDesignSystemFormBuilder
26
55
  build_id('conditional')
27
56
  end
28
57
 
29
- def attribute_descriptor
30
- build_id(nil, '_', '-')
31
- end
32
-
33
58
  def has_errors?
34
59
  @builder.object.errors.any? &&
35
60
  @builder.object.errors.messages.dig(@attribute_name).present?
36
61
  end
37
62
 
38
- def attribute_identifier
39
- "%<object_name>s[%<attribute_name>s]" % {
40
- object_name: @object_name,
41
- attribute_name: @attribute_name
42
- }
43
- end
44
-
45
63
  def wrap_conditional(block)
46
64
  @builder.content_tag('div', class: conditional_classes, id: conditional_id) do
47
65
  @builder.capture { block.call }
48
66
  end
49
67
  end
50
68
 
69
+ def described_by(*ids)
70
+ ids.flatten.compact.join(' ').presence
71
+ end
72
+
51
73
  private
52
74
 
53
- def build_id(id_type, delimiter = '-', replace = '_', override_attribute_name: nil)
75
+ # Builds the values used for HTML id attributes throughout the builder
76
+ #
77
+ # @param id_type [String] a description of the id's type, eg +hint+, +error+
78
+ # @param delimiter [String] the characters used to 'split' the output
79
+ # @param replace [String] the targets to be replaced by the delimiter
80
+ # @param attribute_name [String] overrides the object's +@attribute_name+
81
+ # @param include_value [Boolean] controls whether or not the value will form part
82
+ # of the final id
83
+ #
84
+ # @return [String] the id composed of object, attribute, value and type
85
+ #
86
+ # @example
87
+ # build_id('hint') #=> "person-name-hint"
88
+ def build_id(id_type, delimiter = '-', replace = '_', attribute_name: nil, include_value: true)
89
+ attribute = attribute_name || @attribute_name
90
+ value = include_value && @value || nil
54
91
  [
55
92
  @object_name,
56
- (override_attribute_name || @attribute_name),
57
- @value,
93
+ attribute,
94
+ value,
58
95
  id_type
59
96
  ]
60
97
  .compact
@@ -9,6 +9,7 @@ module GOVUKDesignSystemFormBuilder
9
9
  # @param [Hash] label configures the associated label
10
10
  # @option label text [String] the label text
11
11
  # @option label size [String] the size of the label font, can be +xl+, +l+, +m+, +s+ or nil
12
+ # @option label tag [Symbol,String] the label's wrapper tag, intended to allow labels to act as page headings
12
13
  # @option args [Hash] args additional arguments are applied as attributes to +input+ element
13
14
  # @return [ActiveSupport::SafeBuffer] HTML output
14
15
  # @see https://design-system.service.gov.uk/components/text-input/ GOV.UK Text input
@@ -32,6 +33,7 @@ module GOVUKDesignSystemFormBuilder
32
33
  # @param [Hash] label configures the associated label
33
34
  # @option label text [String] the label text
34
35
  # @option label size [String] the size of the label font, can be +xl+, +l+, +m+, +s+ or nil
36
+ # @option label tag [Symbol,String] the label's wrapper tag, intended to allow labels to act as page headings
35
37
  # @option args [Hash] args additional arguments are applied as attributes to +input+ element
36
38
  # @return [ActiveSupport::SafeBuffer] HTML output
37
39
  # @see https://design-system.service.gov.uk/components/text-input/ GOV.UK Text input
@@ -56,6 +58,7 @@ module GOVUKDesignSystemFormBuilder
56
58
  # @param [Hash] label configures the associated label
57
59
  # @option label text [String] the label text
58
60
  # @option label size [String] the size of the label font, can be +xl+, +l+, +m+, +s+ or nil
61
+ # @option label tag [Symbol,String] the label's wrapper tag, intended to allow labels to act as page headings
59
62
  # @option args [Hash] args additional arguments are applied as attributes to +input+ element
60
63
  # @return [ActiveSupport::SafeBuffer] HTML output
61
64
  # @see https://design-system.service.gov.uk/components/text-input/ GOV.UK Text input
@@ -78,6 +81,7 @@ module GOVUKDesignSystemFormBuilder
78
81
  # @param [Hash] label configures the associated label
79
82
  # @option label text [String] the label text
80
83
  # @option label size [String] the size of the label font, can be +xl+, +l+, +m+, +s+ or nil
84
+ # @option label tag [Symbol,String] the label's wrapper tag, intended to allow labels to act as page headings
81
85
  # @option args [Hash] args additional arguments are applied as attributes to +input+ element
82
86
  # @return [ActiveSupport::SafeBuffer] HTML output
83
87
  # @see https://design-system.service.gov.uk/components/text-input/ GOV.UK Text input
@@ -100,6 +104,7 @@ module GOVUKDesignSystemFormBuilder
100
104
  # @param [Hash] label configures the associated label
101
105
  # @option label text [String] the label text
102
106
  # @option label size [String] the size of the label font, can be +xl+, +l+, +m+, +s+ or nil
107
+ # @option label tag [Symbol,String] the label's wrapper tag, intended to allow labels to act as page headings
103
108
  # @option args [Hash] args additional arguments are applied as attributes to the +input+ element
104
109
  # @return [ActiveSupport::SafeBuffer] HTML output
105
110
  # @see https://design-system.service.gov.uk/components/text-input/ GOV.UK Text input
@@ -124,6 +129,7 @@ module GOVUKDesignSystemFormBuilder
124
129
  # @param [Hash] label configures the associated label
125
130
  # @option label text [String] the label text
126
131
  # @option label size [String] the size of the label font, can be +xl+, +l+, +m+, +s+ or nil
132
+ # @option label tag [Symbol,String] the label's wrapper tag, intended to allow labels to act as page headings
127
133
  # @param max_words [Integer] adds the GOV.UK max word count
128
134
  # @param max_chars [Integer] adds the GOV.UK max characters count
129
135
  # @param threshold [Integer] only show the +max_words+ and +max_chars+ warnings once a threshold (percentage) is reached
@@ -152,37 +158,22 @@ module GOVUKDesignSystemFormBuilder
152
158
  # @param hint_text [String] The content of the hint. No hint will be injected if left +nil+
153
159
  # @option label text [String] the label text
154
160
  # @option label size [String] the size of the label font, can be +xl+, +l+, +m+, +s+ or nil
161
+ # @option label tag [Symbol,String] the label's wrapper tag, intended to allow labels to act as page headings
155
162
  # @return [ActiveSupport::SafeBuffer] HTML output
156
- def govuk_collection_select(attribute_name, collection, value_method, text_method, options: {}, html_options: { class: 'govuk-select' }, hint_text: nil, label: {})
157
- label_element = Elements::Label.new(self, object_name, attribute_name, label)
158
- hint_element = Elements::Hint.new(self, object_name, attribute_name, hint_text)
159
- error_element = Elements::ErrorMessage.new(self, object_name, attribute_name)
160
-
161
- Containers::FormGroup.new(self, object_name, attribute_name).html do
162
- safe_join([
163
- label_element.html,
164
- hint_element.html,
165
- error_element.html,
166
-
167
- (yield if block_given?),
168
-
169
- collection_select(
170
- attribute_name,
171
- collection,
172
- value_method,
173
- text_method,
174
- options,
175
- html_options.merge(
176
- aria: {
177
- describedby: [
178
- hint_element.hint_id,
179
- error_element.error_id
180
- ].compact.join(' ').presence
181
- }
182
- )
183
- )
184
- ])
185
- end
163
+ def govuk_collection_select(attribute_name, collection, value_method, text_method, options: {}, html_options: {}, hint_text: nil, label: {}, &block)
164
+ Elements::Select.new(
165
+ self,
166
+ object_name,
167
+ attribute_name,
168
+ collection,
169
+ value_method: value_method,
170
+ text_method: text_method,
171
+ hint_text: hint_text,
172
+ label: label,
173
+ options: options,
174
+ html_options: html_options,
175
+ &block
176
+ ).html
186
177
  end
187
178
 
188
179
  # Generates a radio button for each item in the supplied collection
@@ -196,7 +187,7 @@ module GOVUKDesignSystemFormBuilder
196
187
  # @param text_method [Symbol] The method called against each member of the collection to provide the text
197
188
  # @param hint_method [Symbol] The method called against each member of the collection to provide the hint text
198
189
  # @param hint_text [String] The content of the fieldset hint. No hint will be injected if left +nil+
199
- # @param legend [Hash] options for configuring the hash
190
+ # @param legend [Hash] options for configuring the legend
200
191
  # @param inline [Boolean] controls whether the radio buttons are displayed inline or not
201
192
  # @param small [Boolean] controls whether small radio buttons are used instead of regular-sized ones
202
193
  # @option legend text [String] the fieldset legend's text content
@@ -219,29 +210,21 @@ module GOVUKDesignSystemFormBuilder
219
210
  # legend: { text: 'Pick your favourite colour', size: 'm' },
220
211
  # hint_text: 'If you cannot find the exact match choose something close',
221
212
  # inline: false
222
- def govuk_collection_radio_buttons(attribute_name, collection, value_method, text_method, hint_method = nil, hint_text: nil, legend: { text: nil, size: 'm' }, inline: false, small: false)
223
- hint_element = Elements::Hint.new(self, object_name, attribute_name, hint_text)
224
- error_element = Elements::ErrorMessage.new(self, object_name, attribute_name)
225
-
226
- Containers::FormGroup.new(self, object_name, attribute_name).html do
227
- Containers::Fieldset.new(self, legend: legend, described_by: [error_element.error_id, hint_element.hint_id]).html do
228
- safe_join(
229
- [
230
- hint_element.html,
231
- error_element.html,
232
-
233
- (yield if block_given?),
234
- Containers::Radios.new(self, inline: inline, small: small).html do
235
- safe_join(
236
- collection.map do |item|
237
- Elements::Radios::CollectionRadio.new(self, object_name, attribute_name, item, value_method, text_method, hint_method).html
238
- end
239
- )
240
- end
241
- ].compact
242
- )
243
- end
244
- end
213
+ def govuk_collection_radio_buttons(attribute_name, collection, value_method, text_method, hint_method = nil, hint_text: nil, legend: { text: nil, size: 'm' }, inline: false, small: false, &block)
214
+ Elements::Radios::Collection.new(
215
+ self,
216
+ object_name,
217
+ attribute_name,
218
+ collection,
219
+ value_method: value_method,
220
+ text_method: text_method,
221
+ hint_method: hint_method,
222
+ hint_text: hint_text,
223
+ legend: legend,
224
+ inline: inline,
225
+ small: small,
226
+ &block
227
+ ).html
245
228
  end
246
229
 
247
230
  # Generates a radio button fieldset container and injects the supplied block contents
@@ -250,12 +233,13 @@ module GOVUKDesignSystemFormBuilder
250
233
  #
251
234
  # @param attribute_name [Symbol] The name of the attribute
252
235
  # @param hint_text [String] The content of the fieldset hint. No hint will be injected if left +nil+
253
- # @param legend [Hash] options for configuring the hash
236
+ # @param legend [Hash] options for configuring the legend
254
237
  # @param inline [Boolean] controls whether the radio buttons are displayed inline or not
255
238
  # @param small [Boolean] controls whether small radio buttons are used instead of regular-sized ones
256
239
  # @option legend text [String] the fieldset legend's text content
257
240
  # @option legend size [String] the size of the fieldset legend font, can be +xl+, +l+, +m+ or +s+
258
241
  # @option legend tag [Symbol,String] the tag used for the fieldset's header, defaults to +h1+
242
+ # @param block [Block] a block of HTML that will be used to populate the fieldset
259
243
  # @see https://design-system.service.gov.uk/components/radios/ GOV.UK Radios
260
244
  # @return [ActiveSupport::SafeBuffer] HTML output
261
245
  #
@@ -267,21 +251,8 @@ module GOVUKDesignSystemFormBuilder
267
251
  # = f.govuk_radio_divider
268
252
  # = f.govuk_radio_button :favourite_colour, :yellow, label: { text: 'Yellow' }
269
253
  #
270
- def govuk_radio_buttons_fieldset(attribute_name, hint_text: nil, legend: {}, inline: false, small: false)
271
- hint_element = Elements::Hint.new(self, object_name, attribute_name, hint_text)
272
- error_element = Elements::ErrorMessage.new(self, object_name, attribute_name)
273
-
274
- Containers::FormGroup.new(self, object_name, attribute_name).html do
275
- Containers::Fieldset.new(self, legend: legend, described_by: [error_element.error_id, hint_element.hint_id]).html do
276
- safe_join([
277
- hint_element.html,
278
- error_element.html,
279
- Containers::Radios.new(self, inline: inline, small: small).html do
280
- yield
281
- end
282
- ])
283
- end
284
- end
254
+ def govuk_radio_buttons_fieldset(attribute_name, hint_text: nil, legend: {}, inline: false, small: false, &block)
255
+ Containers::RadioButtonsFieldset.new(self, object_name, attribute_name, hint_text: hint_text, legend: legend, inline: inline, small: small, &block).html
285
256
  end
286
257
 
287
258
  # Generates a radio button
@@ -295,6 +266,8 @@ module GOVUKDesignSystemFormBuilder
295
266
  # @see https://design-system.service.gov.uk/components/radios/ GOV.UK Radios
296
267
  # @param block [Block] Any supplied HTML will be wrapped in a conditional
297
268
  # container and only revealed when the radio button is picked
269
+ # @param link_errors [Boolean] controls whether this radio button should be linked to
270
+ # from the error summary. <b>Should only be set to +true+ for the first radio button in a fieldset</b>
298
271
  # @return [ActiveSupport::SafeBuffer] HTML output
299
272
  #
300
273
  # @example A collection of radio buttons for favourite colours with a divider
@@ -302,8 +275,8 @@ module GOVUKDesignSystemFormBuilder
302
275
  # = f.govuk_collection_radio_buttons :favourite_colour, inline: false do
303
276
  # = f.govuk_radio_button :favourite_colour, :red, label: { text: 'Red' } do
304
277
  #
305
- def govuk_radio_button(attribute_name, value, hint_text: nil, label: {}, &block)
306
- Elements::Radios::FieldsetRadio.new(self, object_name, attribute_name, value, hint_text: hint_text, label: label, &block).html
278
+ def govuk_radio_button(attribute_name, value, hint_text: nil, label: {}, link_errors: false, &block)
279
+ Elements::Radios::FieldsetRadioButton.new(self, object_name, attribute_name, value, hint_text: hint_text, label: label, link_errors: link_errors, &block).html
307
280
  end
308
281
 
309
282
  # Inserts a text divider into a list of radio buttons
@@ -327,7 +300,7 @@ module GOVUKDesignSystemFormBuilder
327
300
  # @param hint_method [Symbol] The method called against each member of the collection to provide the hint text
328
301
  # @param hint_text [String] The content of the fieldset hint. No hint will be injected if left +nil+
329
302
  # @param small [Boolean] controls whether small check boxes are used instead of regular-sized ones
330
- # @param legend [Hash] options for configuring the hash
303
+ # @param legend [Hash] options for configuring the legend
331
304
  # @option legend text [String] the fieldset legend's text content
332
305
  # @option legend size [String] the size of the fieldset legend font, can be +xl+, +l+, +m+ or +s+
333
306
  # @option legend tag [Symbol,String] the tag used for the fieldset's header, defaults to +h1+
@@ -350,25 +323,84 @@ module GOVUKDesignSystemFormBuilder
350
323
  # hint_text: "If it isn't listed here, tough luck",
351
324
  # inline: false
352
325
  def govuk_collection_check_boxes(attribute_name, collection, value_method, text_method, hint_method = nil, hint_text: nil, legend: {}, small: false, &block)
353
- hint_element = Elements::Hint.new(self, object_name, attribute_name, hint_text)
354
- error_element = Elements::ErrorMessage.new(self, object_name, attribute_name)
326
+ Elements::CheckBoxes::Collection.new(
327
+ self,
328
+ object_name,
329
+ attribute_name,
330
+ collection,
331
+ value_method: value_method,
332
+ text_method: text_method,
333
+ hint_method: hint_method,
334
+ hint_text: hint_text,
335
+ legend: legend,
336
+ small: small,
337
+ &block
338
+ ).html
339
+ end
340
+
341
+ # Generate a fieldset intended to conatain one or more {#govuk_check_box}
342
+ #
343
+ # @param attribute_name [Symbol] The name of the attribute
344
+ # @param hint_text [String] The content of the fieldset hint. No hint will be injected if left +nil+
345
+ # @param small [Boolean] controls whether small check boxes are used instead of regular-sized ones
346
+ # @param legend [Hash] options for configuring the legend
347
+ # @option legend text [String] the fieldset legend's text content
348
+ # @option legend size [String] the size of the fieldset legend font, can be +xl+, +l+, +m+ or +s+
349
+ # @option legend tag [Symbol,String] the tag used for the fieldset's header, defaults to +h1+
350
+ # @param block [Block] a block of HTML that will be used to populate the fieldset
351
+ # @return [ActiveSupport::SafeBuffer] HTML output
352
+ #
353
+ # @example A collection of check boxes for sandwich fillings
354
+ #
355
+ # = f.govuk_check_boxes_fieldset :desired_filling,
356
+ # = f.govuk_check_box :desired_filling, :cheese, label: { text: 'Cheese' }, link_errors: true
357
+ # = f.govuk_check_box :desired_filling, :tomato, label: { text: 'Tomato' }
358
+ #
359
+ def govuk_check_boxes_fieldset(attribute_name, legend: {}, hint_text: {}, small: false, &block)
360
+ Containers::CheckBoxesFieldset.new(
361
+ self,
362
+ object_name,
363
+ attribute_name,
364
+ hint_text: hint_text,
365
+ legend: legend,
366
+ small: small,
367
+ &block
368
+ ).html
369
+ end
355
370
 
356
- Containers::FormGroup.new(self, object_name, attribute_name).html do
357
- Containers::Fieldset.new(self, legend: legend, described_by: [error_element.error_id, hint_element.hint_id]).html do
358
- safe_join(
359
- [
360
- hint_element.html,
361
- error_element.html,
362
- (block.call if block_given?),
363
- Containers::CheckBoxes.new(self, small: small).html do
364
- collection_check_boxes(attribute_name, collection, value_method, text_method) do |check_box|
365
- Elements::CheckBoxes::CollectionCheckBox.new(self, attribute_name, check_box, hint_method).html
366
- end
367
- end
368
- ]
369
- )
370
- end
371
- end
371
+ # Generates a single fieldset, intended for use within a {#govuk_check_boxes_fieldset}
372
+ #
373
+ # @param attribute_name [Symbol] The name of the attribute
374
+ # @param value [Boolean,String,Symbol,Integer] The value of the checkbox when it is checked
375
+ # @param hint_text [String] the contents of the hint
376
+ # @param link_errors [Boolean] controls whether this radio button should be linked to
377
+ # @option label text [String] the label text
378
+ # @option label size [String] the size of the label font, can be +xl+, +l+, +m+, +s+ or nil
379
+ # @option label tag [Symbol,String] the label's wrapper tag, intended to allow labels to act as page headings
380
+ # @param multiple [Boolean] controls whether the check box is part of a collection or represents a single attribute
381
+ # @param block [Block] any HTML passed in will form the contents of the fieldset
382
+ # @return [ActiveSupport::SafeBuffer] HTML output
383
+ #
384
+ # @example A single check box for terms and conditions
385
+ # = f.govuk_check_box :terms_agreed,
386
+ # true,
387
+ # multiple: false,
388
+ # link_errors: true,
389
+ # label: { text: 'Do you agree with our terms and conditions?' },
390
+ # hint_text: 'You will not be able to proceed unless you do'
391
+ #
392
+ def govuk_check_box(attribute_name, value, hint_text: nil, label: {}, link_errors: false, multiple: true, &block)
393
+ Elements::CheckBoxes::FieldsetCheckBox.new(
394
+ self,
395
+ object_name,
396
+ attribute_name,
397
+ value,
398
+ hint_text: hint_text,
399
+ label: label,
400
+ link_errors: link_errors,
401
+ multiple: multiple,
402
+ &block
403
+ ).html
372
404
  end
373
405
 
374
406
  # Generates a submit button, green by default
@@ -408,7 +440,7 @@ module GOVUKDesignSystemFormBuilder
408
440
  # be 'rounded' up to +2019-10-01+.
409
441
  # @param attribute_name [Symbol] The name of the attribute
410
442
  # @param hint_text [String] the contents of the hint
411
- # @param legend [Hash] options for configuring the hash
443
+ # @param legend [Hash] options for configuring the legend
412
444
  # @option legend text [String] the fieldset legend's text content
413
445
  # @option legend size [String] the size of the fieldset legend font, can be +xl+, +l+, +m+ or +s+
414
446
  # @option legend tag [Symbol,String] the tag used for the fieldset's header, defaults to +h1+
@@ -448,7 +480,7 @@ module GOVUKDesignSystemFormBuilder
448
480
 
449
481
  # Generates a fieldset containing the contents of the block
450
482
  #
451
- # @param legend [Hash] options for configuring the hash
483
+ # @param legend [Hash] options for configuring the legend
452
484
  # @param described_by [Array<String>] the ids of the elements that describe this fieldset, usually hints and errors
453
485
  # @option legend text [String] the fieldset legend's text content
454
486
  # @option legend size [String] the size of the fieldset legend font, can be +xl+, +l+, +m+ or +s+
@@ -465,5 +497,27 @@ module GOVUKDesignSystemFormBuilder
465
497
  def govuk_fieldset(legend: { text: 'Fieldset heading' }, described_by: nil, &block)
466
498
  Containers::Fieldset.new(self, legend: legend, described_by: described_by).html(&block)
467
499
  end
500
+
501
+ # Generates an input of type +file+
502
+ #
503
+ # @param attribute_name [Symbol] The name of the attribute
504
+ # @option label text [String] the label text
505
+ # @option label tag [Symbol,String] the label's wrapper tag, intended to allow labels to act as page headings
506
+ # @option label size [String] the size of the label font, can be +xl+, +l+, +m+, +s+ or nil
507
+ # @param hint_text [String] The content of the hint. No hint will be injected if left +nil+
508
+ # @option args [Hash] args additional arguments are applied as attributes to +input+ element
509
+ #
510
+ # @example A photo upload field with file type specifier
511
+ # = f.govuk_file_field :photo, label: { text: 'Upload your photo' }, accept: 'image/*'
512
+ #
513
+ # @see https://design-system.service.gov.uk/components/file-upload/ GOV.UK file upload
514
+ # @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file MDN documentation for file upload
515
+ #
516
+ # @note Remember to set +multipart: true+ when creating a form with file
517
+ # uploads, {https://guides.rubyonrails.org/form_helpers.html#uploading-files see
518
+ # the Rails documentation} for more information
519
+ def govuk_file_field(attribute_name, label: {}, hint_text: nil, **args)
520
+ Elements::File.new(self, object_name, attribute_name, label: label, hint_text: hint_text, **args).html
521
+ end
468
522
  end
469
523
  end