govuk_design_system_formbuilder 1.2.0b1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/govuk_design_system_formbuilder.rb +2 -1
  4. data/lib/govuk_design_system_formbuilder/base.rb +5 -0
  5. data/lib/govuk_design_system_formbuilder/builder.rb +205 -77
  6. data/lib/govuk_design_system_formbuilder/containers/check_boxes_fieldset.rb +12 -11
  7. data/lib/govuk_design_system_formbuilder/containers/fieldset.rb +32 -16
  8. data/lib/govuk_design_system_formbuilder/containers/radio_buttons_fieldset.rb +12 -11
  9. data/lib/govuk_design_system_formbuilder/elements/caption.rb +34 -0
  10. data/lib/govuk_design_system_formbuilder/elements/check_boxes/collection.rb +11 -13
  11. data/lib/govuk_design_system_formbuilder/elements/check_boxes/collection_check_box.rb +17 -15
  12. data/lib/govuk_design_system_formbuilder/elements/check_boxes/fieldset_check_box.rb +20 -27
  13. data/lib/govuk_design_system_formbuilder/elements/date.rb +23 -25
  14. data/lib/govuk_design_system_formbuilder/elements/error_message.rb +8 -7
  15. data/lib/govuk_design_system_formbuilder/elements/error_summary.rb +23 -26
  16. data/lib/govuk_design_system_formbuilder/elements/file.rb +18 -19
  17. data/lib/govuk_design_system_formbuilder/elements/hint.rb +1 -4
  18. data/lib/govuk_design_system_formbuilder/elements/label.rb +30 -19
  19. data/lib/govuk_design_system_formbuilder/elements/radios/collection.rb +26 -24
  20. data/lib/govuk_design_system_formbuilder/elements/radios/collection_radio_button.rb +13 -13
  21. data/lib/govuk_design_system_formbuilder/elements/radios/fieldset_radio_button.rb +15 -19
  22. data/lib/govuk_design_system_formbuilder/elements/select.rb +8 -18
  23. data/lib/govuk_design_system_formbuilder/elements/submit.rb +27 -23
  24. data/lib/govuk_design_system_formbuilder/elements/text_area.rb +17 -23
  25. data/lib/govuk_design_system_formbuilder/traits/caption.rb +23 -0
  26. data/lib/govuk_design_system_formbuilder/traits/input.rb +19 -27
  27. data/lib/govuk_design_system_formbuilder/traits/label.rb +12 -1
  28. data/lib/govuk_design_system_formbuilder/traits/localisation.rb +2 -0
  29. data/lib/govuk_design_system_formbuilder/version.rb +1 -1
  30. metadata +21 -47
@@ -4,10 +4,11 @@ module GOVUKDesignSystemFormBuilder
4
4
  include Traits::Error
5
5
  include Traits::Hint
6
6
 
7
- def initialize(builder, object_name, attribute_name, hint_text:, legend:, small:, classes:, &block)
7
+ def initialize(builder, object_name, attribute_name, hint_text:, legend:, caption:, small:, classes:, &block)
8
8
  super(builder, object_name, attribute_name, &block)
9
9
 
10
10
  @legend = legend
11
+ @caption = caption
11
12
  @hint_text = hint_text
12
13
  @small = small
13
14
  @classes = classes
@@ -16,19 +17,19 @@ module GOVUKDesignSystemFormBuilder
16
17
 
17
18
  def html
18
19
  Containers::FormGroup.new(@builder, @object_name, @attribute_name).html do
19
- Containers::Fieldset.new(@builder, @object_name, @attribute_name, legend: @legend, described_by: [error_element.error_id, hint_element.hint_id]).html do
20
- safe_join(
21
- [
22
- hint_element.html,
23
- error_element.html,
24
- Containers::CheckBoxes.new(@builder, small: @small, classes: @classes).html do
25
- @block_content
26
- end
27
- ]
28
- )
20
+ Containers::Fieldset.new(@builder, @object_name, @attribute_name, legend: @legend, caption: @caption, described_by: [error_element.error_id, hint_element.hint_id]).html do
21
+ safe_join([hint_element, error_element, checkboxes])
29
22
  end
30
23
  end
31
24
  end
25
+
26
+ private
27
+
28
+ def checkboxes
29
+ Containers::CheckBoxes.new(@builder, small: @small, classes: @classes).html do
30
+ @block_content
31
+ end
32
+ end
32
33
  end
33
34
  end
34
35
  end
@@ -3,45 +3,52 @@ module GOVUKDesignSystemFormBuilder
3
3
  class Fieldset < Base
4
4
  using PrefixableArray
5
5
 
6
+ include Traits::Caption
6
7
  include Traits::Localisation
7
8
 
8
9
  LEGEND_SIZES = %w(xl l m s).freeze
9
10
 
10
- def initialize(builder, object_name = nil, attribute_name = nil, legend: {}, described_by: nil)
11
- super(builder, object_name, attribute_name)
11
+ def initialize(builder, object_name = nil, attribute_name = nil, legend: {}, caption: {}, described_by: nil, &block)
12
+ super(builder, object_name, attribute_name, &block)
12
13
 
13
- @legend = legend_defaults.merge(legend)
14
14
  @described_by = described_by(described_by)
15
15
  @attribute_name = attribute_name
16
+
17
+ case legend
18
+ when Proc
19
+ @legend_raw = legend.call
20
+ when Hash
21
+ @legend_options = legend_defaults.merge(legend)
22
+ @caption = caption
23
+ else
24
+ fail(ArgumentError, %(legend must be a Proc or Hash))
25
+ end
16
26
  end
17
27
 
18
28
  def html
19
29
  content_tag('fieldset', class: fieldset_classes, aria: { describedby: @described_by }) do
20
- safe_join([build_legend, yield])
30
+ safe_join([legend_content, (@block_content || yield)])
21
31
  end
22
32
  end
23
33
 
24
34
  private
25
35
 
26
- def legend_defaults
27
- {
28
- hidden: false,
29
- text: nil,
30
- tag: config.default_legend_tag,
31
- size: config.default_legend_size
32
- }
36
+ def legend_content
37
+ @legend_raw || legend
33
38
  end
34
39
 
35
- def build_legend
40
+ def legend
36
41
  if legend_text.present?
37
42
  content_tag('legend', class: legend_classes) do
38
- tag.send(@legend.dig(:tag), legend_text, class: legend_heading_classes)
43
+ content_tag(@legend_options.dig(:tag), class: legend_heading_classes) do
44
+ safe_join([caption_element, legend_text])
45
+ end
39
46
  end
40
47
  end
41
48
  end
42
49
 
43
50
  def legend_text
44
- [@legend.dig(:text), localised_text(:legend)].compact.first
51
+ [@legend_options.dig(:text), localised_text(:legend)].compact.first
45
52
  end
46
53
 
47
54
  def fieldset_classes
@@ -49,17 +56,26 @@ module GOVUKDesignSystemFormBuilder
49
56
  end
50
57
 
51
58
  def legend_classes
52
- size = @legend.dig(:size)
59
+ size = @legend_options.dig(:size)
53
60
  fail "invalid size '#{size}', must be #{LEGEND_SIZES.join(', ')}" unless size.in?(LEGEND_SIZES)
54
61
 
55
62
  [%(fieldset__legend), %(fieldset__legend--#{size})].prefix(brand).tap do |classes|
56
- classes.push(%(#{brand}-visually-hidden)) if @legend.dig(:hidden)
63
+ classes.push(%(#{brand}-visually-hidden)) if @legend_options.dig(:hidden)
57
64
  end
58
65
  end
59
66
 
60
67
  def legend_heading_classes
61
68
  %w(fieldset__heading).prefix(brand)
62
69
  end
70
+
71
+ def legend_defaults
72
+ {
73
+ hidden: false,
74
+ text: nil,
75
+ tag: config.default_legend_tag,
76
+ size: config.default_legend_size
77
+ }
78
+ end
63
79
  end
64
80
  end
65
81
  end
@@ -4,12 +4,13 @@ module GOVUKDesignSystemFormBuilder
4
4
  include Traits::Hint
5
5
  include Traits::Error
6
6
 
7
- def initialize(builder, object_name, attribute_name, hint_text:, legend:, inline:, small:, classes:, &block)
7
+ def initialize(builder, object_name, attribute_name, hint_text:, legend:, caption:, inline:, small:, classes:, &block)
8
8
  super(builder, object_name, attribute_name)
9
9
 
10
10
  @inline = inline
11
11
  @small = small
12
12
  @legend = legend
13
+ @caption = caption
13
14
  @hint_text = hint_text
14
15
  @classes = classes
15
16
  @block_content = capture { block.call }
@@ -17,19 +18,19 @@ module GOVUKDesignSystemFormBuilder
17
18
 
18
19
  def html
19
20
  Containers::FormGroup.new(@builder, @object_name, @attribute_name).html do
20
- Containers::Fieldset.new(@builder, @object_name, @attribute_name, legend: @legend, described_by: [error_element.error_id, hint_element.hint_id]).html do
21
- safe_join(
22
- [
23
- hint_element.html,
24
- error_element.html,
25
- Containers::Radios.new(@builder, inline: @inline, small: @small, classes: @classes).html do
26
- @block_content
27
- end
28
- ]
29
- )
21
+ Containers::Fieldset.new(@builder, @object_name, @attribute_name, legend: @legend, caption: @caption, described_by: [error_element.error_id, hint_element.hint_id]).html do
22
+ safe_join([hint_element, error_element, radios])
30
23
  end
31
24
  end
32
25
  end
26
+
27
+ private
28
+
29
+ def radios
30
+ Containers::Radios.new(@builder, inline: @inline, small: @small, classes: @classes).html do
31
+ @block_content
32
+ end
33
+ end
33
34
  end
34
35
  end
35
36
  end
@@ -0,0 +1,34 @@
1
+ module GOVUKDesignSystemFormBuilder
2
+ module Elements
3
+ class Caption < Base
4
+ include Traits::Localisation
5
+
6
+ def initialize(builder, object_name, attribute_name, text:, size: 'm')
7
+ super(builder, object_name, attribute_name)
8
+
9
+ @text = caption_text(text)
10
+ @size_class = caption_size_class(size)
11
+ end
12
+
13
+ def html
14
+ return nil if @text.blank?
15
+
16
+ tag.span(@text, class: @size_class)
17
+ end
18
+
19
+ def caption_text(override)
20
+ override || localised_text(:caption)
21
+ end
22
+
23
+ def caption_size_class(size)
24
+ case size
25
+ when 'xl' then %(#{brand}-caption-xl)
26
+ when 'l' then %(#{brand}-caption-l)
27
+ when 'm' then %(#{brand}-caption-m)
28
+ else
29
+ fail ArgumentError, "invalid size '#{size}', must be xl, l or m"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -6,7 +6,7 @@ module GOVUKDesignSystemFormBuilder
6
6
  include Traits::Hint
7
7
  include Traits::Supplemental
8
8
 
9
- def initialize(builder, object_name, attribute_name, collection, value_method:, text_method:, hint_method: nil, hint_text:, legend:, small:, classes:, &block)
9
+ def initialize(builder, object_name, attribute_name, collection, value_method:, text_method:, hint_method: nil, hint_text:, legend:, caption:, small:, classes:, &block)
10
10
  super(builder, object_name, attribute_name, &block)
11
11
 
12
12
  @collection = collection
@@ -15,29 +15,27 @@ module GOVUKDesignSystemFormBuilder
15
15
  @hint_method = hint_method
16
16
  @small = small
17
17
  @legend = legend
18
+ @caption = caption
18
19
  @hint_text = hint_text
19
20
  @classes = classes
20
21
  end
21
22
 
22
23
  def html
23
24
  Containers::FormGroup.new(@builder, @object_name, @attribute_name).html do
24
- Containers::Fieldset.new(@builder, @object_name, @attribute_name, legend: @legend, described_by: [error_id, hint_id, supplemental_id]).html do
25
- safe_join(
26
- [
27
- supplemental_content.html,
28
- hint_element.html,
29
- error_element.html,
30
- Containers::CheckBoxes.new(@builder, small: @small, classes: @classes).html do
31
- build_collection
32
- end
33
- ]
34
- )
25
+ Containers::Fieldset.new(@builder, @object_name, @attribute_name, legend: @legend, caption: @caption, described_by: [error_id, hint_id, supplemental_id]).html do
26
+ safe_join([supplemental_content, hint_element, error_element, check_boxes])
35
27
  end
36
28
  end
37
29
  end
38
30
 
39
31
  private
40
32
 
33
+ def check_boxes
34
+ Containers::CheckBoxes.new(@builder, small: @small, classes: @classes).html do
35
+ collection
36
+ end
37
+ end
38
+
41
39
  # Builds a collection of check {Elements::CheckBoxes::CheckBox}
42
40
  # @return [ActiveSupport::SafeBuffer] HTML output
43
41
  #
@@ -46,7 +44,7 @@ module GOVUKDesignSystemFormBuilder
46
44
  # be rendered when it happens we need to work on the chance that it might, so
47
45
  # the +link_errors+ variable is set to +true+ if this attribute has errors and
48
46
  # always set back to +false+ after the first checkbox has been rendered
49
- def build_collection
47
+ def collection
50
48
  link_errors = has_errors?
51
49
 
52
50
  @builder.collection_check_boxes(@attribute_name, @collection, @value_method, @text_method) do |check_box|
@@ -10,31 +10,33 @@ module GOVUKDesignSystemFormBuilder
10
10
  def initialize(builder, object_name, attribute_name, checkbox, hint_method = nil, link_errors: false)
11
11
  super(builder, object_name, attribute_name)
12
12
 
13
- @checkbox = checkbox
14
- @item = checkbox.object
15
- @value = checkbox.value
16
- @hint_text = retrieve(@item, hint_method)
13
+ @checkbox = checkbox
14
+ @item = checkbox.object
15
+ @value = checkbox.value
16
+ @hint_text = retrieve(@item, hint_method)
17
17
  @link_errors = link_errors
18
18
  end
19
19
 
20
20
  def html
21
21
  content_tag('div', class: %(#{brand}-checkboxes__item)) do
22
- safe_join(
23
- [
24
- @checkbox.check_box(
25
- id: field_id(link_errors: @link_errors),
26
- class: %(#{brand}-checkboxes__input),
27
- aria: { describedby: hint_id }
28
- ),
29
- label_element.html,
30
- hint_element.html
31
- ]
32
- )
22
+ safe_join([check_box, label_element, hint_element])
33
23
  end
34
24
  end
35
25
 
36
26
  private
37
27
 
28
+ def check_box
29
+ @checkbox.check_box(**check_box_options)
30
+ end
31
+
32
+ def check_box_options
33
+ {
34
+ id: field_id(link_errors: @link_errors),
35
+ class: %(#{brand}-checkboxes__input),
36
+ aria: { describedby: hint_id }
37
+ }
38
+ end
39
+
38
40
  def label_element
39
41
  @label_element ||= Label.new(@builder, @object_name, @attribute_name, @checkbox, value: @value, link_errors: @link_errors)
40
42
  end
@@ -4,6 +4,7 @@ module GOVUKDesignSystemFormBuilder
4
4
  class FieldsetCheckBox < Base
5
5
  using PrefixableArray
6
6
 
7
+ include Traits::Label
7
8
  include Traits::Hint
8
9
  include Traits::Conditional
9
10
 
@@ -23,41 +24,33 @@ module GOVUKDesignSystemFormBuilder
23
24
  end
24
25
 
25
26
  def html
26
- safe_join(
27
- [
28
- content_tag('div', class: %(#{brand}-checkboxes__item)) do
29
- safe_join(
30
- [
31
- input,
32
- label_element.html,
33
- hint_element.html,
34
- ]
35
- )
36
- end,
37
- @conditional_content
38
- ]
39
- )
27
+ safe_join([check_box, @conditional_content])
40
28
  end
41
29
 
42
30
  private
43
31
 
32
+ def check_box
33
+ content_tag('div', class: %(#{brand}-checkboxes__item)) do
34
+ safe_join([input, label_element, hint_element])
35
+ end
36
+ end
37
+
44
38
  def input
45
- @builder.check_box(
46
- @attribute_name,
47
- {
48
- id: field_id(link_errors: @link_errors),
49
- class: check_box_classes,
50
- multiple: @multiple,
51
- aria: { describedby: hint_id },
52
- data: { 'aria-controls' => @conditional_id }
53
- },
54
- @value,
55
- false
56
- )
39
+ @builder.check_box(@attribute_name, input_options, @value, false)
40
+ end
41
+
42
+ def input_options
43
+ {
44
+ id: field_id(link_errors: @link_errors),
45
+ class: check_box_classes,
46
+ multiple: @multiple,
47
+ aria: { describedby: hint_id },
48
+ data: { 'aria-controls' => @conditional_id }
49
+ }
57
50
  end
58
51
 
59
52
  def label_element
60
- @label_element ||= Elements::Label.new(@builder, @object_name, @attribute_name, checkbox: true, value: @value, **@label, link_errors: @link_errors)
53
+ @label_element ||= Elements::Label.new(@builder, @object_name, @attribute_name, checkbox: true, value: @value, link_errors: @link_errors, **label_options)
61
54
  end
62
55
 
63
56
  def hint_element
@@ -9,10 +9,11 @@ module GOVUKDesignSystemFormBuilder
9
9
 
10
10
  SEGMENTS = { day: '3i', month: '2i', year: '1i' }.freeze
11
11
 
12
- def initialize(builder, object_name, attribute_name, legend:, hint_text:, date_of_birth: false, omit_day:, &block)
12
+ def initialize(builder, object_name, attribute_name, legend:, caption:, hint_text:, date_of_birth: false, omit_day:, &block)
13
13
  super(builder, object_name, attribute_name, &block)
14
14
 
15
15
  @legend = legend
16
+ @caption = caption
16
17
  @hint_text = hint_text
17
18
  @date_of_birth = date_of_birth
18
19
  @omit_day = omit_day
@@ -20,23 +21,20 @@ module GOVUKDesignSystemFormBuilder
20
21
 
21
22
  def html
22
23
  Containers::FormGroup.new(@builder, @object_name, @attribute_name).html do
23
- Containers::Fieldset.new(@builder, @object_name, @attribute_name, legend: @legend, described_by: [error_id, hint_id, supplemental_id]).html do
24
- safe_join(
25
- [
26
- supplemental_content.html,
27
- hint_element.html,
28
- error_element.html,
29
- content_tag('div', class: %(#{brand}-date-input)) do
30
- safe_join([day, month, year])
31
- end
32
- ]
33
- )
24
+ Containers::Fieldset.new(@builder, @object_name, @attribute_name, legend: @legend, caption: @caption, described_by: [error_id, hint_id, supplemental_id]).html do
25
+ safe_join([supplemental_content, hint_element, error_element, date])
34
26
  end
35
27
  end
36
28
  end
37
29
 
38
30
  private
39
31
 
32
+ def date
33
+ content_tag('div', class: %(#{brand}-date-input)) do
34
+ safe_join([day, month, year])
35
+ end
36
+ end
37
+
40
38
  def omit_day?
41
39
  @omit_day
42
40
  end
@@ -44,18 +42,18 @@ module GOVUKDesignSystemFormBuilder
44
42
  def day
45
43
  return nil if omit_day?
46
44
 
47
- date_input_item(:day, link_errors: true)
45
+ date_part_input(:day, link_errors: true)
48
46
  end
49
47
 
50
48
  def month
51
- date_input_item(:month, link_errors: omit_day?)
49
+ date_part_input(:month, link_errors: omit_day?)
52
50
  end
53
51
 
54
52
  def year
55
- date_input_item(:year, width: 4)
53
+ date_part_input(:year, width: 4)
56
54
  end
57
55
 
58
- def date_input_item(segment, width: 2, link_errors: false)
56
+ def date_part_input(segment, width: 2, link_errors: false)
59
57
  value = @builder.object.try(@attribute_name).try(segment)
60
58
 
61
59
  content_tag('div', class: %w(date-input__item).prefix(brand)) do
@@ -64,14 +62,14 @@ module GOVUKDesignSystemFormBuilder
64
62
  [
65
63
  tag.label(
66
64
  segment.capitalize,
67
- class: date_input_label_classes,
68
- for: date_attribute_id(segment, link_errors)
65
+ class: date_part_label_classes,
66
+ for: date_part_attribute_id(segment, link_errors)
69
67
  ),
70
68
 
71
69
  tag.input(
72
- id: date_attribute_id(segment, link_errors),
73
- class: date_input_classes(width),
74
- name: date_attribute_name(segment),
70
+ id: date_part_attribute_id(segment, link_errors),
71
+ class: date_part_input_classes(width),
72
+ name: date_part_attribute_name(segment),
75
73
  type: 'text',
76
74
  pattern: '[0-9]*',
77
75
  inputmode: 'numeric',
@@ -84,21 +82,21 @@ module GOVUKDesignSystemFormBuilder
84
82
  end
85
83
  end
86
84
 
87
- def date_input_classes(width)
85
+ def date_part_input_classes(width)
88
86
  %w(input date-input__input).prefix(brand).tap do |classes|
89
87
  classes.push(%(#{brand}-input--width-#{width}))
90
88
  classes.push(%(#{brand}-input--error)) if has_errors?
91
89
  end
92
90
  end
93
91
 
94
- def date_input_label_classes
92
+ def date_part_label_classes
95
93
  %w(label date-input__label).prefix(brand)
96
94
  end
97
95
 
98
96
  # if the field has errors we want the govuk_error_summary to
99
97
  # be able to link to the day field. Otherwise, generate IDs
100
98
  # in the normal fashion
101
- def date_attribute_id(segment, link_errors)
99
+ def date_part_attribute_id(segment, link_errors)
102
100
  if has_errors? && link_errors
103
101
  field_id(link_errors: link_errors)
104
102
  else
@@ -106,7 +104,7 @@ module GOVUKDesignSystemFormBuilder
106
104
  end
107
105
  end
108
106
 
109
- def date_attribute_name(segment)
107
+ def date_part_attribute_name(segment)
110
108
  format(
111
109
  "%<object_name>s[%<attribute_name>s(%<segment>s)]",
112
110
  object_name: @object_name,