govuk_design_system_formbuilder 0.7.0 → 0.7.1

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: fb762e8a359cd08175a12d4589052ea02fe5d30cdd74b0d970ba8b52c8ac09c2
4
- data.tar.gz: a190f9073ebcd4d59abb9c62485be024f729343544fbc278c2dbbb3d5949b14a
3
+ metadata.gz: 843bd26d3611fad40854e1bdfc5864617e64f90ffc51ededfcf1af0a74f4d2ae
4
+ data.tar.gz: 530a95ed1fb38467f56ef2904110d153c8b1fe5832d5226914f38ae482c8aca7
5
5
  SHA512:
6
- metadata.gz: 20a8147da81aa6add15ec3500ffd849e18ef5f29add89a4d10511d90be78eca08a278315ae17036c5c5ae1e7861408d27133c8f2dcb84faf30e032b7219b142c
7
- data.tar.gz: 5f1e669b7248b062727a7b960aa4448c216a9ad4d30d5ead7314d8989430925b31fd700ed7cd34d4613e0c81465a358d61d59ca4ff47abc8a161b145338e8879
6
+ metadata.gz: 129ddeaf0fba3811dfd02b6730af2e30adfe1c7a312744aea73ee8bafddade947d92912f86f6e94b94307385b9a6f7dfbf2f58487e4b5d4345c5dc2d53cc1ebd
7
+ data.tar.gz: 8ff31c945db767cb82dff353e7355e52f1901d6dc7e517f08f6b6a40ed5816bde09a1832f428b9c1c4d9f71304d64f539acbc9dfdd26e4ccccecd5cd2661ab73
data/README.md CHANGED
@@ -1 +1,78 @@
1
- # GOV.UK Form Builder
1
+ # GOV.UK Design System Form Builder for Rails
2
+
3
+ ## What's included
4
+
5
+ * 100% compatibility with the GOV.UK Design System
6
+ * Full control of labels, hints, fieldsets and legends
7
+ * No overwriting of Rails' default form helpers
8
+ * Automatic ARIA associations between hints, errors and inputs
9
+ * Most helpers take a block for arbitrary content
10
+ * Additional params for programmatically adding hints to check box and radio
11
+ button collections
12
+
13
+ ## Installation
14
+
15
+ You can install the form builder gem by running the `gem install
16
+ govuk_design_system_formbuilder` or by adding the following line
17
+ to your `Gemfile`
18
+
19
+ ```sh
20
+ gem 'govuk_design_system_formbuilder'
21
+ ```
22
+
23
+ ## Setup
24
+
25
+ To use the form builder in an ad hoc basis you can specify it
26
+ as an argument to `form_for`
27
+
28
+
29
+ ```slim
30
+ = form_for @some_object, builder: GOVUKDesignSystemFormBuilder::FormBuilder do |f|
31
+ ```
32
+
33
+ To set it globally, just add this to your `ApplicationController`
34
+
35
+ ```ruby
36
+ class ApplicationController < ActionController::Base
37
+ default_form_builder GOVUKDesignSystemFormBuilder::FormBuilder
38
+ end
39
+ ```
40
+
41
+ Now we can get started! 🎉
42
+
43
+ ```slim
44
+ = form_for @person do |f|
45
+
46
+ = f.govuk_text_field :full_name, label: { text: 'Your full name' }
47
+
48
+ = f.govuk_number_field :age, label: { text: 'Age' }
49
+
50
+ = f.submit 'Away we go!'
51
+ ```
52
+
53
+ ## Developing and running the tests
54
+
55
+ The form builder is covered by RSpec, to run all the tests first ensure that
56
+ all of the development and testing prerequisite gems are installed. At the root
57
+ of a freshly-cloned repo run
58
+
59
+ ```sh
60
+ bundle
61
+ ```
62
+
63
+ Now, if everything was successful, run RSpec
64
+
65
+ ```sh
66
+ rspec -fd
67
+ ```
68
+
69
+ ## Thanks
70
+
71
+ This project was inspired by [MoJ's GovukElementsFormBuilder](https://github.com/ministryofjustice/govuk_elements_form_builder),
72
+ but tackles some problems in a different manner. It provides the following
73
+ advantages by providing:
74
+
75
+ * no reliance on a custom proxy/block buffer
76
+ * idiomatic Ruby
77
+ * a modular codebase
78
+ * a more-robust test suite
@@ -6,10 +6,8 @@ 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/radio'
10
9
  require 'govuk_design_system_formbuilder/elements/radios/collection_radio'
11
10
  require 'govuk_design_system_formbuilder/elements/radios/fieldset_radio'
12
- require 'govuk_design_system_formbuilder/elements/check_box'
13
11
  require 'govuk_design_system_formbuilder/elements/check_boxes/collection_check_box'
14
12
  require 'govuk_design_system_formbuilder/elements/check_boxes/label'
15
13
  require 'govuk_design_system_formbuilder/elements/check_boxes/hint'
@@ -11,19 +11,19 @@ module GOVUKDesignSystemFormBuilder
11
11
  end
12
12
 
13
13
  def hint_id
14
- return nil unless @text.present?
14
+ return nil unless @hint_text.present?
15
15
 
16
- @hint_id || [@object_name, @attribute_name, 'hint'].join('-').parameterize
16
+ [@object_name, @attribute_name, @value, 'hint'].compact.join('-').parameterize
17
17
  end
18
18
 
19
19
  def error_id
20
20
  return nil unless has_errors?
21
21
 
22
- [@object_name, @attribute_name, 'error'].join('-').parameterize
22
+ [@object_name, @attribute_name, 'error'].compact.join('-').parameterize
23
23
  end
24
24
 
25
25
  def conditional_id
26
- [@object_name, @attribute_name, @value, 'conditional'].join('-').parameterize
26
+ [@object_name, @attribute_name, @value, 'conditional'].compact.join('-').parameterize
27
27
  end
28
28
 
29
29
  def has_errors?
@@ -41,5 +41,12 @@ module GOVUKDesignSystemFormBuilder
41
41
  attribute_name: @attribute_name
42
42
  }
43
43
  end
44
+
45
+ def wrap_conditional(block)
46
+ conditional = @builder.content_tag('div', class: conditional_classes, id: conditional_id) do
47
+ @builder.capture { block.call }
48
+ end
49
+ return conditional, conditional_id
50
+ end
44
51
  end
45
52
  end
@@ -1,35 +1,150 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
2
  module Builder
3
- def govuk_text_field(attribute_name, hint: {}, label: {}, **args)
4
- Elements::Input.new(self, object_name, attribute_name, attribute_type: :text, hint: hint, label: label, **args).html
3
+
4
+ # Generates a input of type `text`
5
+ #
6
+ # @param attribute_name [Symbol] The name of the attribute
7
+ # @param hint_text [String] The content of the hint. No hint will be injected if left +nil+
8
+ # @param [Hash] label configures the associated label
9
+ # @option label text [String] the label text
10
+ # @option label size [String] the size of the label font, can be +large+, +medium+, +regular+ or +small+
11
+ # @option label weight [String] the weight of the label font, can be +bold+ or +regular+
12
+ # @option args [Hash] args additional arguments are applied as attributes to +input+ element
13
+ # @return [ActiveSupport::SafeBuffer] HTML output
14
+ #
15
+ # @example A required full name field with a placeholder
16
+ # = govuk_text_field :name,
17
+ # label: { text: 'Full name' },
18
+ # hint_text: 'It says it on your birth certificate',
19
+ # required: true,
20
+ # placeholder: 'Ralph Wiggum'
21
+ def govuk_text_field(attribute_name, hint_text: nil, label: {}, **args)
22
+ Elements::Input.new(self, object_name, attribute_name, attribute_type: :text, hint_text: hint_text, label: label, **args).html
5
23
  end
6
24
 
7
- def govuk_phone_field(attribute_name, hint: {}, label: {}, **args)
8
- Elements::Input.new(self, object_name, attribute_name, attribute_type: :phone, hint: hint, label: label, **args).html
25
+ # Generates a input of type `tel`
26
+ #
27
+ # @param attribute_name [Symbol] The name of the attribute
28
+ # @param hint_text [String] The content of the hint. No hint will be injected if left +nil+
29
+ # @param [Hash] label configures the associated label
30
+ # @option label text [String] the label text
31
+ # @option label size [String] the size of the label font, can be +large+, +medium+, +regular+ or +small+
32
+ # @option label weight [String] the weight of the label font, can be +bold+ or +regular+
33
+ # @option args [Hash] args additional arguments are applied as attributes to +input+ element
34
+ # @return [ActiveSupport::SafeBuffer] HTML output
35
+ #
36
+ # @example A required phone number field with a placeholder
37
+ # = govuk_phone_field :phone_number,
38
+ # label: { text: 'UK telephone number' },
39
+ # hint_text: 'Include the dialling code',
40
+ # required: true,
41
+ # placeholder: '0123 456 789'
42
+ def govuk_phone_field(attribute_name, hint_text: nil, label: {}, **args)
43
+ Elements::Input.new(self, object_name, attribute_name, attribute_type: :phone, hint_text: hint_text, label: label, **args).html
9
44
  end
10
45
 
11
- def govuk_email_field(attribute_name, hint: {}, label: {}, **args)
12
- Elements::Input.new(self, object_name, attribute_name, attribute_type: :email, hint: hint, label: label, **args).html
46
+ # Generates a input of type `email`
47
+ #
48
+ # @param attribute_name [Symbol] The name of the attribute
49
+ # @param hint_text [String] The content of the hint. No hint will be injected if left +nil+
50
+ # @param [Hash] label configures the associated label
51
+ # @option label text [String] the label text
52
+ # @option label size [String] the size of the label font, can be +large+, +medium+, +regular+ or +small+
53
+ # @option label weight [String] the weight of the label font, can be +bold+ or +regular+
54
+ # @option args [Hash] args additional arguments are applied as attributes to +input+ element
55
+ # @return [ActiveSupport::SafeBuffer] HTML output
56
+ #
57
+ # @example An email address field with a placeholder
58
+ # = govuk_email_field :email_address,
59
+ # label: { text: 'Enter your email address' },
60
+ # placeholder: 'ralph.wiggum@springfield.edu'
61
+ def govuk_email_field(attribute_name, hint_text: nil, label: {}, **args)
62
+ Elements::Input.new(self, object_name, attribute_name, attribute_type: :email, hint_text: hint_text, label: label, **args).html
13
63
  end
14
64
 
15
- def govuk_url_field(attribute_name, hint: {}, label: {}, **args)
16
- Elements::Input.new(self, object_name, attribute_name, attribute_type: :url, hint: hint, label: label, **args).html
65
+ # Generates a input of type `url`
66
+ #
67
+ # @param attribute_name [Symbol] The name of the attribute
68
+ # @param hint_text [String] The content of the hint. No hint will be injected if left +nil+
69
+ # @param [Hash] label configures the associated label
70
+ # @option label text [String] the label text
71
+ # @option label size [String] the size of the label font, can be +large+, +medium+, +regular+ or +small+
72
+ # @option label weight [String] the weight of the label font, can be +bold+ or +regular+
73
+ # @option args [Hash] args additional arguments are applied as attributes to +input+ element
74
+ # @return [ActiveSupport::SafeBuffer] HTML output
75
+ #
76
+ # @example A url field with autocomplete
77
+ # = govuk_url_field :favourite_website,
78
+ # label: { text: 'Enter your favourite website' },
79
+ # placeholder: 'https://www.gov.uk',
80
+ # autocomplete: 'url'
81
+ def govuk_url_field(attribute_name, hint_text: nil, label: {}, **args)
82
+ Elements::Input.new(self, object_name, attribute_name, attribute_type: :url, hint_text: hint_text, label: label, **args).html
17
83
  end
18
84
 
19
- def govuk_number_field(attribute_name, hint: {}, label: {}, **args)
20
- Elements::Input.new(self, object_name, attribute_name, attribute_type: :number, hint: hint, label: label, **args).html
85
+ # Generates a input of type `number`
86
+ #
87
+ # @param attribute_name [Symbol] The name of the attribute
88
+ # @param hint_text [String] The content of the hint. No hint will be injected if left +nil+
89
+ # @param [Hash] label configures the associated label
90
+ # @option label text [String] the label text
91
+ # @option label size [String] the size of the label font, can be +large+, +medium+, +regular+ or +small+
92
+ # @option label weight [String] the weight of the label font, can be +bold+ or +regular+
93
+ # @option args [Hash] args additional arguments are applied as attributes to the +input+ element
94
+ # @return [ActiveSupport::SafeBuffer] HTML output
95
+ #
96
+ # @example A number field with placeholder, min, max and step
97
+ # = govuk_number_field :iq,
98
+ # label: { text: 'What is your IQ?' },
99
+ # placeholder: 100,
100
+ # min: 80,
101
+ # max: 150,
102
+ # step: 5
103
+ def govuk_number_field(attribute_name, hint_text: nil, label: {}, **args)
104
+ Elements::Input.new(self, object_name, attribute_name, attribute_type: :number, hint_text: hint_text, label: label, **args).html
21
105
  end
22
106
 
23
- def govuk_text_area(attribute_name, hint: {}, label: {}, max_words: nil, max_chars: nil, rows: 5, **args)
24
- Elements::TextArea.new(self, object_name, attribute_name, hint: hint, label: label, max_words: max_words, max_chars: max_chars, rows: rows, **args).html
107
+
108
+ # Generates a +textarea+ element with a label, optional hint. Also offers
109
+ # the ability to add the GOV.UK character and word counting components
110
+ # automatically
111
+ #
112
+ # @param attribute_name [Symbol] The name of the attribute
113
+ # @param hint_text [String] The content of the hint. No hint will be injected if left +nil+
114
+ # @param [Hash] label configures the associated label
115
+ # @option label text [String] the label text
116
+ # @option label size [String] the size of the label font, can be +large+, +medium+, +regular+ or +small+
117
+ # @option label weight [String] the weight of the label font, can be +bold+ or +regular+
118
+ # @param max_words [Integer] adds the GOV.UK max word count
119
+ # @param max_chars [Integer] adds the GOV.UK max characters count
120
+ # @option args [Hash] args additional arguments are applied as attributes to the +textarea+ element
121
+ # @return [ActiveSupport::SafeBuffer] HTML output
122
+ # @see https://design-system.service.gov.uk/components/character-count GOV.UK character count component
123
+ # @note Setting +max_chars+ or +max_words+ will add a caption beneath the +textarea+ with a live count of words
124
+ # or characters
125
+ #
126
+ # @example A number field with placeholder, min, max and step
127
+ # = govuk_number_field :cv,
128
+ # label: { text: 'Tell us about your work history' },
129
+ # rows: 8,
130
+ # max_words: 300
131
+ def govuk_text_area(attribute_name, hint_text: nil, label: {}, max_words: nil, max_chars: nil, rows: 5, **args)
132
+ Elements::TextArea.new(self, object_name, attribute_name, hint_text: hint_text, label: label, max_words: max_words, max_chars: max_chars, rows: rows, **args).html
25
133
  end
26
134
 
27
- # FIXME #govuk_collection_select args differ from Rails' #collection_select args in that
28
- # options: and :html_options are keyword arguments. Leaving them as regular args with
29
- # defaults and following them with keyword args (hint and label) doesn't seem to work
30
- def govuk_collection_select(attribute_name, collection, value_method, text_method, options: {}, html_options: {}, hint: {}, label: {})
135
+ # Generates a +select+ element containing +option+ for each member in the provided collection
136
+ #
137
+ # @param attribute_name [Symbol] The name of the attribute
138
+ # @param collection [Enumerable<Object>] Options to be added to the +select+ element
139
+ # @param value_method [Symbol] The method called against each member of the collection to provide the value
140
+ # @param text_method [Symbol] The method called against each member of the collection to provide the text
141
+ # @param hint_text [String] The content of the hint. No hint will be injected if left +nil+
142
+ # @option label text [String] the label text
143
+ # @option label size [String] the size of the label font, can be +large+, +medium+, +regular+ or +small+
144
+ # @option label weight [String] the weight of the label font, can be +bold+ or +regular+
145
+ def govuk_collection_select(attribute_name, collection, value_method, text_method, options: {}, html_options: {}, hint_text: nil, label: {})
31
146
  label_element = Elements::Label.new(self, object_name, attribute_name, label)
32
- hint_element = Elements::Hint.new(self, object_name, attribute_name, hint)
147
+ hint_element = Elements::Hint.new(self, object_name, attribute_name, hint_text)
33
148
  error_element = Elements::ErrorMessage.new(self, object_name, attribute_name)
34
149
 
35
150
  Containers::FormGroup.new(self, object_name, attribute_name).html do
@@ -59,105 +174,83 @@ module GOVUKDesignSystemFormBuilder
59
174
  end
60
175
  end
61
176
 
62
- def govuk_collection_radio_buttons(attribute_name, collection, value_method, text_method, hint_method = nil, options: { inline: false }, html_options: {}, hint: {}, legend: {})
63
- hint_element = Elements::Hint.new(self, object_name, attribute_name, hint)
177
+ def govuk_collection_radio_buttons(attribute_name, collection, value_method, text_method, hint_method = nil, options: { inline: false }, html_options: {}, hint_text: nil, legend: {})
178
+ hint_element = Elements::Hint.new(self, object_name, attribute_name, hint_text)
179
+ error_element = Elements::ErrorMessage.new(self, object_name, attribute_name)
180
+
64
181
  Containers::FormGroup.new(self, object_name, attribute_name).html do
65
- safe_join(
66
- [
67
- hint_element.html,
68
- Containers::Fieldset.new(self, object_name, attribute_name, legend: legend, described_by: hint_element.hint_id).html do
69
- safe_join(
70
- [
71
- (yield if block_given?),
72
- Containers::Radios.new(self, inline: options.dig(:inline)).html do
73
- safe_join(
74
- collection.map do |item|
75
- Elements::Radios::CollectionRadio.new(self, object_name, attribute_name, item, value_method, text_method, hint_method).html
76
- end
77
- )
182
+ Containers::Fieldset.new(self, object_name, attribute_name, legend: legend, described_by: [error_element.error_id, hint_element.hint_id]).html do
183
+ safe_join(
184
+ [
185
+ hint_element.html,
186
+ error_element.html,
187
+
188
+ (yield if block_given?),
189
+ Containers::Radios.new(self, inline: options.dig(:inline)).html do
190
+ safe_join(
191
+ collection.map do |item|
192
+ Elements::Radios::CollectionRadio.new(self, object_name, attribute_name, item, value_method, text_method, hint_method).html
78
193
  end
79
- ].compact
80
- )
81
- end
82
- ]
83
- )
194
+ )
195
+ end
196
+ ].compact
197
+ )
198
+ end
84
199
  end
85
200
  end
86
201
 
87
- def govuk_radio_buttons_fieldset(attribute_name, options: { inline: false }, hint: {}, legend: {})
88
- hint_element = Elements::Hint.new(self, object_name, attribute_name, hint)
202
+ def govuk_radio_buttons_fieldset(attribute_name, options: { inline: false }, hint_text: nil, legend: {})
203
+ hint_element = Elements::Hint.new(self, object_name, attribute_name, hint_text)
204
+ error_element = Elements::ErrorMessage.new(self, object_name, attribute_name)
89
205
 
90
206
  Containers::FormGroup.new(self, object_name, attribute_name).html do
91
- safe_join([
92
- hint_element.html,
93
- Containers::Fieldset.new(self, object_name, attribute_name, legend: legend, described_by: hint_element.hint_id).html do
207
+ Containers::Fieldset.new(self, object_name, attribute_name, legend: legend, described_by: [error_element.error_id, hint_element.hint_id]).html do
208
+ safe_join([
209
+ hint_element.html,
210
+ error_element.html,
94
211
  Containers::Radios.new(self, inline: options.dig(:inline)).html do
95
212
  yield
96
213
  end
97
- end
98
- ])
214
+ ])
215
+ end
99
216
  end
100
217
  end
101
218
 
102
219
  # only intended for use inside a #govuk_radio_buttons_fieldset
103
- def govuk_radio_button(attribute_name, value, hint: {}, label: {})
104
- Elements::Radios::FieldsetRadio.new(self, object_name, attribute_name, value, hint: hint, label: label).html do
105
- (yield if block_given?)
106
- end
220
+ def govuk_radio_button(attribute_name, value, hint_text: nil, label: {}, &block)
221
+ Elements::Radios::FieldsetRadio.new(self, object_name, attribute_name, value, hint_text: hint_text, label: label, &block).html
107
222
  end
108
223
 
109
224
  def govuk_radio_divider(text = 'or')
110
225
  tag.div(text, class: %w(govuk-radios__divider))
111
226
  end
112
227
 
113
- def govuk_collection_check_boxes(attribute_name, collection, value_method, text_method, hint_method = nil, html_options: {}, hint: {}, legend: {})
114
- hint_element = Elements::Hint.new(self, object_name, attribute_name, hint)
228
+ def govuk_collection_check_boxes(attribute_name, collection, value_method, text_method, hint_method = nil, html_options: {}, hint_text: nil, legend: {})
229
+ hint_element = Elements::Hint.new(self, object_name, attribute_name, hint_text)
230
+ error_element = Elements::ErrorMessage.new(self, object_name, attribute_name)
231
+
115
232
  Containers::FormGroup.new(self, object_name, attribute_name).html do
116
- safe_join(
117
- [
118
- hint_element.html,
119
- (yield if block_given?),
120
- Containers::Fieldset.new(self, object_name, attribute_name, legend: legend, described_by: hint_element.hint_id).html do
233
+ Containers::Fieldset.new(self, object_name, attribute_name, legend: legend, described_by: [error_element.error_id, hint_element.hint_id]).html do
234
+ safe_join(
235
+ [
236
+ hint_element.html,
237
+ error_element.html,
238
+ (yield if block_given?),
121
239
  collection_check_boxes(attribute_name, collection, value_method, text_method) do |check_box|
122
240
  Elements::CheckBoxes::CollectionCheckBox.new(self, attribute_name, check_box, hint_method).html
123
241
  end
124
- end
125
- ]
126
- )
127
- end
128
- end
129
-
130
- def govuk_check_boxes_fieldset(attribute_name, html_options: {}, hint: {}, legend: {})
131
- hint_element = Elements::Hint.new(self, object_name, attribute_name, hint)
132
-
133
- Containers::FormGroup.new(self, object_name, attribute_name).html do
134
- safe_join([
135
- hint_element.html,
136
- Containers::Fieldset.new(self, object_name, attribute_name, legend: legend, described_by: hint_element.hint_id).html do
137
- Containers::CheckBoxes.new(self).html do
138
- yield
139
- end
140
- end
141
- ])
142
- end
143
- end
144
-
145
- def govuk_check_box(attribute_name, value, hint: {}, label: {})
146
- Elements::CheckBox.new(self, object_name, attribute_name, value, hint: hint, label: label).html do
147
- (yield if block_given?)
242
+ ]
243
+ )
244
+ end
148
245
  end
149
246
  end
150
247
 
151
- def govuk_submit(text = 'Continue', warning: false, secondary: false, prevent_double_click: true)
152
- Elements::Submit.new(self, text, warning: warning, secondary: secondary, prevent_double_click: prevent_double_click).html do
153
- (yield if block_given?)
154
- end
248
+ def govuk_submit(text = 'Continue', warning: false, secondary: false, prevent_double_click: true, &block)
249
+ Elements::Submit.new(self, text, warning: warning, secondary: secondary, prevent_double_click: prevent_double_click, &block).html
155
250
  end
156
251
 
157
- def govuk_date_field(attribute_name, hint: {}, legend: {})
158
- Elements::Date.new(self, object_name, attribute_name, hint: hint, legend: legend).html do
159
- (yield if block_given?)
160
- end
252
+ def govuk_date_field(attribute_name, hint_text: nil, legend: {}, date_of_birth: false, &block)
253
+ Elements::Date.new(self, object_name, attribute_name, hint_text: hint_text, legend: legend, date_of_birth: date_of_birth, &block).html
161
254
  end
162
255
  end
163
256
  end
@@ -2,12 +2,14 @@ module GOVUKDesignSystemFormBuilder
2
2
  module Containers
3
3
  class Fieldset < GOVUKDesignSystemFormBuilder::Base
4
4
  LEGEND_DEFAULTS = { text: nil, tag: 'h1', size: 'xl' }.freeze
5
+
6
+ # FIXME standardise sizes with labels
5
7
  LEGEND_SIZES = %w(xl l m s)
6
8
 
7
9
  def initialize(builder, object_name, attribute_name, legend: {}, described_by: nil)
8
10
  super(builder, object_name, attribute_name)
9
11
  @legend = LEGEND_DEFAULTS.merge(legend)
10
- @described_by = described_by
12
+ @described_by = descriptors(described_by)
11
13
  end
12
14
 
13
15
  def html
@@ -42,6 +44,12 @@ module GOVUKDesignSystemFormBuilder
42
44
  def legend_heading_classes
43
45
  %(govuk-fieldset__heading)
44
46
  end
47
+
48
+ def descriptors(described_by)
49
+ return nil unless described_by.present?
50
+
51
+ Array.wrap(described_by).join(' ')
52
+ end
45
53
  end
46
54
  end
47
55
  end
@@ -3,19 +3,19 @@ module GOVUKDesignSystemFormBuilder
3
3
  module CheckBoxes
4
4
  class CollectionCheckBox < GOVUKDesignSystemFormBuilder::Base
5
5
  def initialize(builder, attribute, checkbox, hint_method = nil)
6
- @builder = builder
6
+ @builder = builder
7
7
  @attribute = attribute
8
- @checkbox = checkbox
9
- @item = checkbox.object
10
- @hint = @item.send(hint_method) if hint_method.present?
8
+ @checkbox = checkbox
9
+ @item = checkbox.object
10
+ @hint_text = @item.send(hint_method) if hint_method.present?
11
11
  end
12
12
 
13
13
  def html
14
- hint = Hint.new(@builder, @attribute, @checkbox, @hint)
14
+ hint = Hint.new(@builder, @attribute, @checkbox, @hint_text)
15
15
  @builder.content_tag('div', class: 'govuk-checkboxes__item') do
16
16
  @builder.safe_join(
17
17
  [
18
- @checkbox.check_box(class: "govuk-checkboxes_input", aria: { describedby: hint.id }),
18
+ @checkbox.check_box(class: "govuk-checkboxes__input", aria: { describedby: hint.id }),
19
19
  Label.new(@checkbox).html,
20
20
  hint.html
21
21
  ]
@@ -3,21 +3,23 @@ module GOVUKDesignSystemFormBuilder
3
3
  class Date < GOVUKDesignSystemFormBuilder::Base
4
4
  SEGMENTS = { day: '3i', month: '2i', year: '1i' }
5
5
 
6
- def initialize(builder, object_name, attribute_name, legend:, hint:)
6
+ def initialize(builder, object_name, attribute_name, legend:, hint_text:, date_of_birth: false, &block)
7
7
  super(builder, object_name, attribute_name)
8
8
  @legend = legend
9
- @hint = hint
9
+ @hint_text = hint_text
10
+ @date_of_birth = date_of_birth
11
+ @block_content = @builder.capture { block.call }.html_safe if block_given?
10
12
  end
11
13
 
12
14
  def html
13
- hint_element = Elements::Hint.new(@builder, @object_name, @attribute_name, @hint)
15
+ hint_element = Elements::Hint.new(@builder, @object_name, @attribute_name, @hint_text)
14
16
 
15
17
  Containers::FormGroup.new(@builder, @object_name, @attribute_name).html do
16
18
  Containers::Fieldset.new(@builder, @object_name, @attribute_name, legend: @legend, described_by: hint_element.hint_id).html do
17
19
  @builder.safe_join(
18
20
  [
19
21
  hint_element.html,
20
- (yield if block_given?),
22
+ @block_content,
21
23
  @builder.content_tag('div', class: 'govuk-date-input') do
22
24
  @builder.safe_join(
23
25
  [
@@ -57,7 +59,8 @@ module GOVUKDesignSystemFormBuilder
57
59
  min: min,
58
60
  max: max,
59
61
  step: 1,
60
- value: value
62
+ value: value,
63
+ autocomplete: date_of_birth_autocomplete_value(segment)
61
64
  )
62
65
  ]
63
66
  )
@@ -84,6 +87,12 @@ module GOVUKDesignSystemFormBuilder
84
87
  segment: SEGMENTS.fetch(segment)
85
88
  }
86
89
  end
90
+
91
+ def date_of_birth_autocomplete_value(segment)
92
+ return nil unless @date_of_birth
93
+
94
+ { day: 'bday-day', month: 'bday-month', year: 'bday-year' }.fetch(segment)
95
+ end
87
96
  end
88
97
  end
89
98
  end
@@ -1,23 +1,32 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
2
  module Elements
3
3
  class Hint < GOVUKDesignSystemFormBuilder::Base
4
- def initialize(builder, object_name, attribute_name, options = {})
4
+ def initialize(builder, object_name, attribute_name, text, value = nil, radio: false, checkbox: false)
5
5
  super(builder, object_name, attribute_name)
6
- @text = options&.dig(:text)
7
- @extra_classes = options&.dig(:class)
8
- @hint_id = options&.dig(:id)
6
+ @value = value
7
+ @hint_text = text
8
+ @radio_class = radio_class(radio)
9
+ @checkbox_class = checkbox_class(checkbox)
9
10
  end
10
11
 
11
12
  def html
12
- return nil unless @text.present?
13
+ return nil unless @hint_text.present?
13
14
 
14
- @builder.tag.span(@text, class: hint_classes, id: hint_id)
15
+ @builder.tag.span(@hint_text, class: hint_classes, id: hint_id)
15
16
  end
16
17
 
17
18
  private
18
19
 
19
20
  def hint_classes
20
- %w(govuk-hint).push(@extra_classes).compact
21
+ %w(govuk-hint).push(@radio_class, @checkbox_class).compact
22
+ end
23
+
24
+ def radio_class(radio)
25
+ radio ? 'govuk-radios__hint' : nil
26
+ end
27
+
28
+ def checkbox_class(checkbox)
29
+ checkbox ? 'govuk-checkboxes__hint' : nil
21
30
  end
22
31
  end
23
32
  end
@@ -1,18 +1,18 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
2
  module Elements
3
3
  class Input < GOVUKDesignSystemFormBuilder::Base
4
- def initialize(builder, object_name, attribute_name, attribute_type:, hint:, label:, **extra_args)
4
+ def initialize(builder, object_name, attribute_name, attribute_type:, hint_text:, label:, **extra_args)
5
5
  super(builder, object_name, attribute_name)
6
6
 
7
- @extra_args = extra_args.dup
8
- @width = @extra_args.delete(:width)
7
+ @extra_args = extra_args.dup
8
+ @width = @extra_args.delete(:width)
9
9
  @builder_method = [attribute_type, 'field'].join('_')
10
- @label = label
11
- @hint = hint
10
+ @label = label
11
+ @hint_text = hint_text
12
12
  end
13
13
 
14
14
  def html
15
- hint_element = Elements::Hint.new(@builder, @object_name, @attribute_name, @hint)
15
+ hint_element = Elements::Hint.new(@builder, @object_name, @attribute_name, @hint_text)
16
16
  label_element = Elements::Label.new(@builder, @object_name, @attribute_name, @label)
17
17
  error_element = Elements::ErrorMessage.new(@builder, @object_name, @attribute_name)
18
18
 
@@ -26,7 +26,6 @@ module GOVUKDesignSystemFormBuilder
26
26
  @builder_method,
27
27
  @attribute_name,
28
28
  class: input_classes,
29
- name: attribute_descriptor,
30
29
  aria: {
31
30
  describedby: [
32
31
  hint_element.hint_id,
@@ -1,13 +1,15 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
2
  module Elements
3
3
  class Label < GOVUKDesignSystemFormBuilder::Base
4
- def initialize(builder, object_name, attribute_name, text: nil, value: nil, size: 'regular', weight: 'regular')
4
+ def initialize(builder, object_name, attribute_name, text: nil, value: nil, size: 'regular', weight: 'regular', radio: false, checkbox: false)
5
5
  super(builder, object_name, attribute_name)
6
6
 
7
- @text = label_text(text)
8
- @value = value # used by attribute_descriptor
9
- @size_class = label_size_class(size)
10
- @weight_class = label_weight_class(weight)
7
+ @text = label_text(text)
8
+ @value = value # used by attribute_descriptor
9
+ @size_class = label_size_class(size)
10
+ @weight_class = label_weight_class(weight)
11
+ @radio_class = radio_class(radio)
12
+ @checkbox_class = checkbox_class(checkbox)
11
13
  end
12
14
 
13
15
  def html
@@ -17,7 +19,7 @@ module GOVUKDesignSystemFormBuilder
17
19
  @attribute_name,
18
20
  @text,
19
21
  value: @value,
20
- class: %w(govuk-label).push(@size_class, @weight_class).compact
22
+ class: %w(govuk-label).push(@size_class, @weight_class, @radio_class, @checkbox_class).compact
21
23
  )
22
24
  end
23
25
 
@@ -27,6 +29,14 @@ module GOVUKDesignSystemFormBuilder
27
29
  [option_text, @value, @attribute_name.capitalize].compact.first
28
30
  end
29
31
 
32
+ def radio_class(radio)
33
+ radio ? 'govuk-radios__label' : nil
34
+ end
35
+
36
+ def checkbox_class(checkbox)
37
+ checkbox ? 'govuk-checkboxes__label' : nil
38
+ end
39
+
30
40
  def label_size_class(size)
31
41
  case size
32
42
  when 'large' then "govuk-!-font-size-48"
@@ -1,13 +1,13 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
2
  module Elements
3
3
  module Radios
4
- class CollectionRadio < Radio
4
+ class CollectionRadio < Base
5
5
  def initialize(builder, object_name, attribute_name, item, value_method, text_method, hint_method)
6
6
  super(builder, object_name, attribute_name)
7
7
  @item = item
8
8
  @value = item.send(value_method)
9
9
  @text = item.send(text_method)
10
- @hint = item.send(hint_method) if hint_method.present?
10
+ @hint_text = item.send(hint_method) if hint_method.present?
11
11
  end
12
12
 
13
13
  def html
@@ -18,10 +18,11 @@ module GOVUKDesignSystemFormBuilder
18
18
  @attribute_name,
19
19
  @value,
20
20
  id: attribute_descriptor,
21
- aria: { describedby: hint_id }
21
+ aria: { describedby: hint_id },
22
+ class: %w(govuk-radios__input)
22
23
  ),
23
24
  Elements::Label.new(@builder, @object_name, @attribute_name, text: @text, value: @value).html,
24
- Elements::Hint.new(@builder, @object_name, @attribute_name, id: hint_id, class: radio_hint_classes, text: @hint).html,
25
+ Elements::Hint.new(@builder, @object_name, @attribute_name, @hint_text, @value, radio: true).html,
25
26
  ].compact
26
27
  )
27
28
  end
@@ -1,24 +1,23 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
2
  module Elements
3
3
  module Radios
4
- class FieldsetRadio < Radio
5
- def initialize(builder, object_name, attribute_name, value, label:, hint:)
4
+ class FieldsetRadio < Base
5
+ def initialize(builder, object_name, attribute_name, value, label:, hint_text:, &block)
6
6
  super(builder, object_name, attribute_name)
7
7
  @value = value
8
8
  @label = label
9
- @hint = hint
9
+ @hint_text = hint_text
10
+ @conditional_content, @conditional_id = wrap_conditional(block) if block_given?
10
11
  end
11
12
 
12
- def html(&block)
13
- @conditional_content, @conditional_id = process(block)
14
-
13
+ def html
15
14
  @builder.content_tag('div', class: 'govuk-radios__item') do
16
15
  @builder.safe_join(
17
16
  [
18
17
  input,
19
- Elements::Label.new(@builder, @object_name, @attribute_name, @label).html,
20
- Elements::Hint.new(@builder, @object_name, @attribute_name, id: hint_id, class: radio_hint_classes, text: @hint).html,
21
- conditional_content
18
+ Elements::Label.new(@builder, @object_name, @attribute_name, radio: true, value: @value, **@label).html,
19
+ Elements::Hint.new(@builder, @object_name, @attribute_name, @hint_text, radio: true).html,
20
+ @conditional_content
22
21
  ]
23
22
  )
24
23
  end
@@ -32,22 +31,11 @@ module GOVUKDesignSystemFormBuilder
32
31
  @value,
33
32
  id: attribute_descriptor,
34
33
  aria: { describedby: hint_id },
35
- data: { 'aria-controls' => @conditional_id }
34
+ data: { 'aria-controls' => @conditional_id },
35
+ class: %w(govuk-radios__input)
36
36
  )
37
37
  end
38
38
 
39
- def conditional_content
40
- return nil unless @conditional_content.present?
41
-
42
- @builder.content_tag('div', class: conditional_classes, id: @conditional_id) do
43
- @conditional_content
44
- end
45
- end
46
-
47
- def process(block)
48
- return content = block.call, (content && conditional_id)
49
- end
50
-
51
39
  def conditional_classes
52
40
  %w(govuk-radios__conditional govuk-radios__conditional--hidden)
53
41
  end
@@ -1,7 +1,7 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
2
  module Elements
3
3
  class Submit < GOVUKDesignSystemFormBuilder::Base
4
- def initialize(builder, text, warning:, secondary:, prevent_double_click:)
4
+ def initialize(builder, text, warning:, secondary:, prevent_double_click:, &block)
5
5
  @builder = builder
6
6
  @text = text
7
7
  @prevent_double_click = prevent_double_click
@@ -9,15 +9,14 @@ module GOVUKDesignSystemFormBuilder
9
9
  fail ArgumentError, 'buttons can be warning or secondary' if (warning && secondary)
10
10
  @warning = warning
11
11
  @secondary = secondary
12
+ @block_content = @builder.capture { block.call } if block_given?
12
13
  end
13
14
 
14
- def html(&block)
15
- content = process(block)
16
-
15
+ def html
17
16
  @builder.content_tag('div', class: %w(govuk-form-group)) do
18
17
  @builder.safe_join([
19
- @builder.submit(@text, class: submit_button_classes(content.present?), **extra_args),
20
- content
18
+ @builder.submit(@text, class: submit_button_classes(@block_content.present?), **extra_args),
19
+ @block_content
21
20
  ])
22
21
  end
23
22
  end
@@ -37,10 +36,6 @@ module GOVUKDesignSystemFormBuilder
37
36
  def extra_args
38
37
  { data: { 'prevent-double-click' => (@prevent_double_click || nil) }.compact }
39
38
  end
40
-
41
- def process(block)
42
- block.call
43
- end
44
39
  end
45
40
  end
46
41
  end
@@ -1,10 +1,10 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
2
  module Elements
3
3
  class TextArea < Base
4
- def initialize(builder, object_name, attribute_name, hint:, label:, rows:, max_words:, max_chars:, **extra_args)
4
+ def initialize(builder, object_name, attribute_name, hint_text:, label:, rows:, max_words:, max_chars:, **extra_args)
5
5
  super(builder, object_name, attribute_name)
6
6
  @label = label
7
- @hint = hint
7
+ @hint_text = hint_text
8
8
  @extra_args = extra_args
9
9
  @max_words = max_words
10
10
  @max_chars = max_chars
@@ -12,7 +12,7 @@ module GOVUKDesignSystemFormBuilder
12
12
  end
13
13
 
14
14
  def html
15
- hint_element = Elements::Hint.new(@builder, @object_name, @attribute_name, @hint)
15
+ hint_element = Elements::Hint.new(@builder, @object_name, @attribute_name, @hint_text)
16
16
  label_element = Elements::Label.new(@builder, @object_name, @attribute_name, @label)
17
17
  error_element = Elements::ErrorMessage.new(@builder, @object_name, @attribute_name)
18
18
 
@@ -1,3 +1,3 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
- VERSION = '0.7.0'.freeze
2
+ VERSION = '0.7.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: govuk_design_system_formbuilder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Yates
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-25 00:00:00.000000000 Z
11
+ date: 2019-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -50,14 +50,14 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: '3.8'
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '0'
60
+ version: '3.8'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: rspec-html-matchers
63
63
  requirement: !ruby/object:Gem::Requirement
@@ -92,28 +92,28 @@ dependencies:
92
92
  requirements:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: '0'
95
+ version: 0.12.2
96
96
  type: :development
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: '0'
102
+ version: 0.12.2
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: pry-byebug
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: '0'
109
+ version: 3.7.0
110
110
  type: :development
111
111
  prerelease: false
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
- version: '0'
116
+ version: 3.7.0
117
117
  description: A Rails form builder that generates form inputs adhering to the GOV.UK
118
118
  Design System
119
119
  email:
@@ -132,7 +132,6 @@ files:
132
132
  - lib/govuk_design_system_formbuilder/containers/fieldset.rb
133
133
  - lib/govuk_design_system_formbuilder/containers/form_group.rb
134
134
  - lib/govuk_design_system_formbuilder/containers/radios.rb
135
- - lib/govuk_design_system_formbuilder/elements/check_box.rb
136
135
  - lib/govuk_design_system_formbuilder/elements/check_boxes/collection_check_box.rb
137
136
  - lib/govuk_design_system_formbuilder/elements/check_boxes/hint.rb
138
137
  - lib/govuk_design_system_formbuilder/elements/check_boxes/label.rb
@@ -141,7 +140,6 @@ files:
141
140
  - lib/govuk_design_system_formbuilder/elements/hint.rb
142
141
  - lib/govuk_design_system_formbuilder/elements/input.rb
143
142
  - lib/govuk_design_system_formbuilder/elements/label.rb
144
- - lib/govuk_design_system_formbuilder/elements/radio.rb
145
143
  - lib/govuk_design_system_formbuilder/elements/radios/collection_radio.rb
146
144
  - lib/govuk_design_system_formbuilder/elements/radios/fieldset_radio.rb
147
145
  - lib/govuk_design_system_formbuilder/elements/submit.rb
@@ -1,84 +0,0 @@
1
- module GOVUKDesignSystemFormBuilder
2
- module Elements
3
- class CheckBox < GOVUKDesignSystemFormBuilder::Base
4
- def initialize(builder, object_name, attribute_name, value, label:, hint:)
5
- super(builder, object_name, attribute_name)
6
- @value = value
7
- @label = label
8
- @hint = hint
9
- end
10
-
11
- def html(&block)
12
- @conditional_content, @conditional_id = process(block)
13
-
14
- @builder.content_tag('div', class: 'govuk-checkboxes__item') do
15
- @builder.safe_join(
16
- [
17
- input,
18
-
19
- Elements::Label.new(
20
- @builder,
21
- @object_name,
22
- @attribute_name,
23
- { value: @value.parameterize, text: @value }.merge(@label)
24
- ).html,
25
-
26
- Elements::Hint.new(
27
- @builder,
28
- @object_name,
29
- @attribute_name,
30
- id: hint_id,
31
- class: check_box_hint_classes,
32
- **@hint
33
- ).html,
34
-
35
- conditional_content
36
- ]
37
- )
38
- end
39
- end
40
-
41
- private
42
-
43
- def input
44
- @builder.check_box(
45
- @attribute_name,
46
- id: attribute_descriptor,
47
- class: check_box_classes,
48
- aria: { describedby: hint_id },
49
- data: { 'aria-controls' => @conditional_id }
50
- )
51
- end
52
-
53
- def conditional_content
54
- return nil unless @conditional_content.present?
55
-
56
- @builder.content_tag('div', class: conditional_classes, id: @conditional_id) do
57
- @conditional_content
58
- end
59
- end
60
-
61
- def process(block)
62
- return content = block.call, (content && conditional_id)
63
- end
64
-
65
- def conditional_classes
66
- %w(govuk-checkboxes__conditional govuk-checkboxes__conditional--hidden)
67
- end
68
-
69
- def hint_id
70
- return nil unless @hint['text'].present?
71
-
72
- [@object_name, @attribute_name, @value, 'hint'].join('-').parameterize
73
- end
74
-
75
- def check_box_classes
76
- %w(govuk-checkbox)
77
- end
78
-
79
- def check_box_hint_classes
80
- %w(govuk-hint govuk-checkboxes__hint)
81
- end
82
- end
83
- end
84
- end
@@ -1,15 +0,0 @@
1
- module GOVUKDesignSystemFormBuilder
2
- module Elements
3
- class Radio < GOVUKDesignSystemFormBuilder::Base
4
- def hint_id
5
- return nil unless @hint.present?
6
-
7
- [@object_name, @attribute_name, @value, 'hint'].join('-').parameterize
8
- end
9
-
10
- def radio_hint_classes
11
- %w(govuk-hint govuk-radios__hint)
12
- end
13
- end
14
- end
15
- end